push 4d5485f9b89f417d46b39b93e8d940437007f325
[wine/hacks.git] / dlls / wined3d / device.c
blob3fd370df31a459b9db3c55c81bdb572c02054037
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-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->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 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
473 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
474 object->contained_transform_states[j - 1] = j;
476 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
477 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
478 object->contained_vs_consts_f[j] = j;
480 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
481 for(j = 0; j < MAX_CONST_I; j++) {
482 object->contained_vs_consts_i[j] = j;
484 object->num_contained_vs_consts_i = MAX_CONST_I;
485 for(j = 0; j < MAX_CONST_B; j++) {
486 object->contained_vs_consts_b[j] = j;
488 object->num_contained_vs_consts_b = MAX_CONST_B;
489 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
490 object->contained_ps_consts_f[j] = j;
492 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
493 for(j = 0; j < MAX_CONST_I; j++) {
494 object->contained_ps_consts_i[j] = j;
496 object->num_contained_ps_consts_i = MAX_CONST_I;
497 for(j = 0; j < MAX_CONST_B; j++) {
498 object->contained_ps_consts_b[j] = j;
500 object->num_contained_ps_consts_b = MAX_CONST_B;
501 for(i = 0; i < MAX_TEXTURES; i++) {
502 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
503 object->contained_tss_states[object->num_contained_tss_states].stage = i;
504 object->contained_tss_states[object->num_contained_tss_states].state = j;
505 object->num_contained_tss_states++;
508 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
509 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
510 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
511 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
512 object->num_contained_sampler_states++;
516 } else if (Type == WINED3DSBT_PIXELSTATE) {
518 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
519 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
521 object->changed.pixelShader = TRUE;
523 /* Pixel Shader Constants */
524 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
525 object->contained_ps_consts_f[i] = i;
526 object->changed.pixelShaderConstantsF[i] = TRUE;
528 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
529 for (i = 0; i < MAX_CONST_B; ++i) {
530 object->contained_ps_consts_b[i] = i;
531 object->changed.pixelShaderConstantsB[i] = TRUE;
533 object->num_contained_ps_consts_b = MAX_CONST_B;
534 for (i = 0; i < MAX_CONST_I; ++i) {
535 object->contained_ps_consts_i[i] = i;
536 object->changed.pixelShaderConstantsI[i] = TRUE;
538 object->num_contained_ps_consts_i = MAX_CONST_I;
540 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
541 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
542 object->contained_render_states[i] = SavedPixelStates_R[i];
544 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
545 for (j = 0; j < MAX_TEXTURES; j++) {
546 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
547 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
548 object->contained_tss_states[object->num_contained_tss_states].stage = j;
549 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
550 object->num_contained_tss_states++;
553 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
554 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
555 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
556 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
557 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
558 object->num_contained_sampler_states++;
562 } else if (Type == WINED3DSBT_VERTEXSTATE) {
564 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
565 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
567 object->changed.vertexShader = TRUE;
569 /* Vertex Shader Constants */
570 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
571 object->changed.vertexShaderConstantsF[i] = TRUE;
572 object->contained_vs_consts_f[i] = i;
574 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
575 for (i = 0; i < MAX_CONST_B; ++i) {
576 object->changed.vertexShaderConstantsB[i] = TRUE;
577 object->contained_vs_consts_b[i] = i;
579 object->num_contained_vs_consts_b = MAX_CONST_B;
580 for (i = 0; i < MAX_CONST_I; ++i) {
581 object->changed.vertexShaderConstantsI[i] = TRUE;
582 object->contained_vs_consts_i[i] = i;
584 object->num_contained_vs_consts_i = MAX_CONST_I;
585 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
586 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
587 object->contained_render_states[i] = SavedVertexStates_R[i];
589 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
590 for (j = 0; j < MAX_TEXTURES; j++) {
591 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
592 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
593 object->contained_tss_states[object->num_contained_tss_states].stage = j;
594 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
595 object->num_contained_tss_states++;
598 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
599 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
600 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
601 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
602 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
603 object->num_contained_sampler_states++;
607 for(j = 0; j < LIGHTMAP_SIZE; j++) {
608 struct list *e;
609 LIST_FOR_EACH(e, &object->lightMap[j]) {
610 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
611 light->changed = TRUE;
612 light->enabledChanged = TRUE;
615 } else {
616 FIXME("Unrecognized state block type %d\n", Type);
619 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
620 return WINED3D_OK;
623 /* ************************************
624 MSDN:
625 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
627 Discard
628 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
630 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.
632 ******************************** */
634 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) {
635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
636 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
637 unsigned int Size = 1;
638 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
639 TRACE("(%p) Create surface\n",This);
641 /** FIXME: Check ranges on the inputs are valid
642 * MSDN
643 * MultisampleQuality
644 * [in] Quality level. The valid range is between zero and one less than the level
645 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
646 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
647 * values of paired render targets, depth stencil surfaces, and the MultiSample type
648 * must all match.
649 *******************************/
653 * TODO: Discard MSDN
654 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
656 * If this flag is set, the contents of the depth stencil buffer will be
657 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
658 * with a different depth surface.
660 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
661 ***************************/
663 if(MultisampleQuality < 0) {
664 FIXME("Invalid multisample level %d\n", MultisampleQuality);
665 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
668 if(MultisampleQuality > 0) {
669 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
670 MultisampleQuality=0;
673 /** FIXME: Check that the format is supported
674 * by the device.
675 *******************************/
677 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
678 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
679 * space!
680 *********************************/
681 if (WINED3DFMT_UNKNOWN == Format) {
682 Size = 0;
683 } else if (Format == WINED3DFMT_DXT1) {
684 /* DXT1 is half byte per pixel */
685 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
687 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
688 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
689 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
690 } else {
691 /* The pitch is a multiple of 4 bytes */
692 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
693 Size *= Height;
696 /** Create and initialise the surface resource **/
697 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
698 /* "Standalone" surface */
699 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
701 object->currentDesc.Width = Width;
702 object->currentDesc.Height = Height;
703 object->currentDesc.MultiSampleType = MultiSample;
704 object->currentDesc.MultiSampleQuality = MultisampleQuality;
705 object->glDescription.level = Level;
707 /* Flags */
708 object->Flags = 0;
709 object->Flags |= Discard ? SFLAG_DISCARD : 0;
710 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
711 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
714 if (WINED3DFMT_UNKNOWN != Format) {
715 object->bytesPerPixel = tableEntry->bpp;
716 } else {
717 object->bytesPerPixel = 0;
720 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
722 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
724 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
725 * this function is too deep to need to care about things like this.
726 * Levels need to be checked too, and possibly Type since they all affect what can be done.
727 * ****************************************/
728 switch(Pool) {
729 case WINED3DPOOL_SCRATCH:
730 if(!Lockable)
731 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
732 "which are mutually exclusive, setting lockable to TRUE\n");
733 Lockable = TRUE;
734 break;
735 case WINED3DPOOL_SYSTEMMEM:
736 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
737 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
738 case WINED3DPOOL_MANAGED:
739 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
740 "Usage of DYNAMIC which are mutually exclusive, not doing "
741 "anything just telling you.\n");
742 break;
743 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
744 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
745 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
746 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
747 break;
748 default:
749 FIXME("(%p) Unknown pool %d\n", This, Pool);
750 break;
753 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
754 FIXME("Trying to create a render target that isn't in the default pool\n");
757 /* mark the texture as dirty so that it gets loaded first time around*/
758 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
759 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
760 This, Width, Height, Format, debug_d3dformat(Format),
761 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
763 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
764 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
765 This->ddraw_primary = (IWineD3DSurface *) object;
767 /* Look at the implementation and set the correct Vtable */
768 switch(Impl) {
769 case SURFACE_OPENGL:
770 /* Check if a 3D adapter is available when creating gl surfaces */
771 if(!This->adapter) {
772 ERR("OpenGL surfaces are not available without opengl\n");
773 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
774 HeapFree(GetProcessHeap(), 0, object);
775 return WINED3DERR_NOTAVAILABLE;
777 break;
779 case SURFACE_GDI:
780 object->lpVtbl = &IWineGDISurface_Vtbl;
781 break;
783 default:
784 /* To be sure to catch this */
785 ERR("Unknown requested surface implementation %d!\n", Impl);
786 IWineD3DSurface_Release((IWineD3DSurface *) object);
787 return WINED3DERR_INVALIDCALL;
790 list_init(&object->renderbuffers);
792 /* Call the private setup routine */
793 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
797 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
798 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
799 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
800 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
803 IWineD3DTextureImpl *object;
804 unsigned int i;
805 UINT tmpW;
806 UINT tmpH;
807 HRESULT hr;
808 unsigned int pow2Width;
809 unsigned int pow2Height;
812 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
813 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
814 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
816 /* TODO: It should only be possible to create textures for formats
817 that are reported as supported */
818 if (WINED3DFMT_UNKNOWN >= Format) {
819 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
820 return WINED3DERR_INVALIDCALL;
823 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
824 D3DINITIALIZEBASETEXTURE(object->baseTexture);
825 object->width = Width;
826 object->height = Height;
828 /** Non-power2 support **/
829 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
830 pow2Width = Width;
831 pow2Height = Height;
832 } else {
833 /* Find the nearest pow2 match */
834 pow2Width = pow2Height = 1;
835 while (pow2Width < Width) pow2Width <<= 1;
836 while (pow2Height < Height) pow2Height <<= 1;
839 /** FIXME: add support for real non-power-two if it's provided by the video card **/
840 /* Precalculated scaling for 'faked' non power of two texture coords */
841 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
842 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
843 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
845 /* Calculate levels for mip mapping */
846 if (Levels == 0) {
847 TRACE("calculating levels %d\n", object->baseTexture.levels);
848 object->baseTexture.levels++;
849 tmpW = Width;
850 tmpH = Height;
851 while (tmpW > 1 || tmpH > 1) {
852 tmpW = max(1, tmpW >> 1);
853 tmpH = max(1, tmpH >> 1);
854 object->baseTexture.levels++;
856 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
859 /* Generate all the surfaces */
860 tmpW = Width;
861 tmpH = Height;
862 for (i = 0; i < object->baseTexture.levels; i++)
864 /* use the callback to create the texture surface */
865 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
866 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
867 FIXME("Failed to create surface %p\n", object);
868 /* clean up */
869 object->surfaces[i] = NULL;
870 IWineD3DTexture_Release((IWineD3DTexture *)object);
872 *ppTexture = NULL;
873 return hr;
876 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
877 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
878 /* calculate the next mipmap level */
879 tmpW = max(1, tmpW >> 1);
880 tmpH = max(1, tmpH >> 1);
883 TRACE("(%p) : Created texture %p\n", This, object);
884 return WINED3D_OK;
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Depth,
889 UINT Levels, DWORD Usage,
890 WINED3DFORMAT Format, WINED3DPOOL Pool,
891 IWineD3DVolumeTexture **ppVolumeTexture,
892 HANDLE *pSharedHandle, IUnknown *parent,
893 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
896 IWineD3DVolumeTextureImpl *object;
897 unsigned int i;
898 UINT tmpW;
899 UINT tmpH;
900 UINT tmpD;
902 /* TODO: It should only be possible to create textures for formats
903 that are reported as supported */
904 if (WINED3DFMT_UNKNOWN >= Format) {
905 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
906 return WINED3DERR_INVALIDCALL;
909 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
910 D3DINITIALIZEBASETEXTURE(object->baseTexture);
912 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
913 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
915 object->width = Width;
916 object->height = Height;
917 object->depth = Depth;
919 /* Calculate levels for mip mapping */
920 if (Levels == 0) {
921 object->baseTexture.levels++;
922 tmpW = Width;
923 tmpH = Height;
924 tmpD = Depth;
925 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
926 tmpW = max(1, tmpW >> 1);
927 tmpH = max(1, tmpH >> 1);
928 tmpD = max(1, tmpD >> 1);
929 object->baseTexture.levels++;
931 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
934 /* Generate all the surfaces */
935 tmpW = Width;
936 tmpH = Height;
937 tmpD = Depth;
939 for (i = 0; i < object->baseTexture.levels; i++)
941 HRESULT hr;
942 /* Create the volume */
943 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
944 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
946 if(FAILED(hr)) {
947 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
948 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
949 *ppVolumeTexture = NULL;
950 return hr;
953 /* Set its container to this object */
954 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
956 /* calcualte the next mipmap level */
957 tmpW = max(1, tmpW >> 1);
958 tmpH = max(1, tmpH >> 1);
959 tmpD = max(1, tmpD >> 1);
962 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
963 TRACE("(%p) : Created volume texture %p\n", This, object);
964 return WINED3D_OK;
967 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
968 UINT Width, UINT Height, UINT Depth,
969 DWORD Usage,
970 WINED3DFORMAT Format, WINED3DPOOL Pool,
971 IWineD3DVolume** ppVolume,
972 HANDLE* pSharedHandle, IUnknown *parent) {
974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
975 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
976 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
978 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
980 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
981 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
983 object->currentDesc.Width = Width;
984 object->currentDesc.Height = Height;
985 object->currentDesc.Depth = Depth;
986 object->bytesPerPixel = formatDesc->bpp;
988 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
989 object->lockable = TRUE;
990 object->locked = FALSE;
991 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
992 object->dirty = TRUE;
994 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
997 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
998 UINT Levels, DWORD Usage,
999 WINED3DFORMAT Format, WINED3DPOOL Pool,
1000 IWineD3DCubeTexture **ppCubeTexture,
1001 HANDLE *pSharedHandle, IUnknown *parent,
1002 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1005 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1006 unsigned int i, j;
1007 UINT tmpW;
1008 HRESULT hr;
1009 unsigned int pow2EdgeLength = EdgeLength;
1011 /* TODO: It should only be possible to create textures for formats
1012 that are reported as supported */
1013 if (WINED3DFMT_UNKNOWN >= Format) {
1014 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1015 return WINED3DERR_INVALIDCALL;
1018 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1019 WARN("(%p) : Tried to create not supported cube texture\n", This);
1020 return WINED3DERR_INVALIDCALL;
1023 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1024 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1026 TRACE("(%p) Create Cube Texture\n", This);
1028 /** Non-power2 support **/
1030 /* Find the nearest pow2 match */
1031 pow2EdgeLength = 1;
1032 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1034 object->edgeLength = EdgeLength;
1035 /* TODO: support for native non-power 2 */
1036 /* Precalculated scaling for 'faked' non power of two texture coords */
1037 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1039 /* Calculate levels for mip mapping */
1040 if (Levels == 0) {
1041 object->baseTexture.levels++;
1042 tmpW = EdgeLength;
1043 while (tmpW > 1) {
1044 tmpW = max(1, tmpW >> 1);
1045 object->baseTexture.levels++;
1047 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1050 /* Generate all the surfaces */
1051 tmpW = EdgeLength;
1052 for (i = 0; i < object->baseTexture.levels; i++) {
1054 /* Create the 6 faces */
1055 for (j = 0; j < 6; j++) {
1057 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1058 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1060 if(hr!= WINED3D_OK) {
1061 /* clean up */
1062 int k;
1063 int l;
1064 for (l = 0; l < j; l++) {
1065 IWineD3DSurface_Release(object->surfaces[j][i]);
1067 for (k = 0; k < i; k++) {
1068 for (l = 0; l < 6; l++) {
1069 IWineD3DSurface_Release(object->surfaces[l][j]);
1073 FIXME("(%p) Failed to create surface\n",object);
1074 HeapFree(GetProcessHeap(),0,object);
1075 *ppCubeTexture = NULL;
1076 return hr;
1078 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1079 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1081 tmpW = max(1, tmpW >> 1);
1084 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1085 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1086 return WINED3D_OK;
1089 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1091 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1092 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1094 /* Just a check to see if we support this type of query */
1095 switch(Type) {
1096 case WINED3DQUERYTYPE_OCCLUSION:
1097 TRACE("(%p) occlusion query\n", This);
1098 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1099 hr = WINED3D_OK;
1100 else
1101 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1102 break;
1104 case WINED3DQUERYTYPE_EVENT:
1105 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1106 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1107 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1109 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1111 hr = WINED3D_OK;
1112 break;
1114 case WINED3DQUERYTYPE_VCACHE:
1115 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1116 case WINED3DQUERYTYPE_VERTEXSTATS:
1117 case WINED3DQUERYTYPE_TIMESTAMP:
1118 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1119 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1120 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1121 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1122 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1123 case WINED3DQUERYTYPE_PIXELTIMINGS:
1124 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1125 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1126 default:
1127 FIXME("(%p) Unhandled query type %d\n", This, Type);
1129 if(NULL == ppQuery || hr != WINED3D_OK) {
1130 return hr;
1133 D3DCREATEOBJECTINSTANCE(object, Query)
1134 object->type = Type;
1135 /* allocated the 'extended' data based on the type of query requested */
1136 switch(Type){
1137 case WINED3DQUERYTYPE_OCCLUSION:
1138 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1139 TRACE("(%p) Allocating data for an occlusion query\n", This);
1140 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1141 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1142 break;
1144 case WINED3DQUERYTYPE_EVENT:
1145 /* TODO: GL_APPLE_fence */
1146 if(GL_SUPPORT(APPLE_FENCE)) {
1147 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1148 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1149 checkGLcall("glGenFencesAPPLE");
1150 } else if(GL_SUPPORT(NV_FENCE)) {
1151 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1152 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1153 checkGLcall("glGenFencesNV");
1155 break;
1157 case WINED3DQUERYTYPE_VCACHE:
1158 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1159 case WINED3DQUERYTYPE_VERTEXSTATS:
1160 case WINED3DQUERYTYPE_TIMESTAMP:
1161 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1162 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1163 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1164 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1165 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1166 case WINED3DQUERYTYPE_PIXELTIMINGS:
1167 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1168 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1169 default:
1170 object->extendedData = 0;
1171 FIXME("(%p) Unhandled query type %d\n",This , Type);
1173 TRACE("(%p) : Created Query %p\n", This, object);
1174 return WINED3D_OK;
1177 /*****************************************************************************
1178 * IWineD3DDeviceImpl_SetupFullscreenWindow
1180 * Helper function that modifies a HWND's Style and ExStyle for proper
1181 * fullscreen use.
1183 * Params:
1184 * iface: Pointer to the IWineD3DDevice interface
1185 * window: Window to setup
1187 *****************************************************************************/
1188 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1191 LONG style, exStyle;
1192 /* Don't do anything if an original style is stored.
1193 * That shouldn't happen
1195 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1196 if (This->style || This->exStyle) {
1197 ERR("(%p): Want to change the window parameters of HWND %p, but "
1198 "another style is stored for restoration afterwards\n", This, window);
1201 /* Get the parameters and save them */
1202 style = GetWindowLongW(window, GWL_STYLE);
1203 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1204 This->style = style;
1205 This->exStyle = exStyle;
1207 /* Filter out window decorations */
1208 style &= ~WS_CAPTION;
1209 style &= ~WS_THICKFRAME;
1210 exStyle &= ~WS_EX_WINDOWEDGE;
1211 exStyle &= ~WS_EX_CLIENTEDGE;
1213 /* Make sure the window is managed, otherwise we won't get keyboard input */
1214 style |= WS_POPUP | WS_SYSMENU;
1216 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1217 This->style, This->exStyle, style, exStyle);
1219 SetWindowLongW(window, GWL_STYLE, style);
1220 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1222 /* Inform the window about the update. */
1223 SetWindowPos(window, HWND_TOP, 0, 0,
1224 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1225 ShowWindow(window, SW_NORMAL);
1228 /*****************************************************************************
1229 * IWineD3DDeviceImpl_RestoreWindow
1231 * Helper function that restores a windows' properties when taking it out
1232 * of fullscreen mode
1234 * Params:
1235 * iface: Pointer to the IWineD3DDevice interface
1236 * window: Window to setup
1238 *****************************************************************************/
1239 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1242 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1243 * switch, do nothing
1245 if (!This->style && !This->exStyle) return;
1247 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1248 This, window, This->style, This->exStyle);
1250 SetWindowLongW(window, GWL_STYLE, This->style);
1251 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1253 /* Delete the old values */
1254 This->style = 0;
1255 This->exStyle = 0;
1257 /* Inform the window about the update */
1258 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1259 0, 0, 0, 0, /* Pos, Size, ignored */
1260 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1263 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1264 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1265 IUnknown* parent,
1266 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1267 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1270 HDC hDc;
1271 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1272 HRESULT hr = WINED3D_OK;
1273 IUnknown *bufferParent;
1275 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1277 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1278 * does a device hold a reference to a swap chain giving them a lifetime of the device
1279 * or does the swap chain notify the device of its destruction.
1280 *******************************/
1282 /* Check the params */
1283 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1284 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1285 return WINED3DERR_INVALIDCALL;
1286 } else if (pPresentationParameters->BackBufferCount > 1) {
1287 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");
1290 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1292 /*********************
1293 * Lookup the window Handle and the relating X window handle
1294 ********************/
1296 /* Setup hwnd we are using, plus which display this equates to */
1297 object->win_handle = pPresentationParameters->hDeviceWindow;
1298 if (!object->win_handle) {
1299 object->win_handle = This->createParms.hFocusWindow;
1302 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1303 hDc = GetDC(object->win_handle);
1304 TRACE("Using hDc %p\n", hDc);
1306 if (NULL == hDc) {
1307 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1308 return WINED3DERR_NOTAVAILABLE;
1311 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1312 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1313 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1314 ReleaseDC(object->win_handle, hDc);
1316 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1317 * then the corresponding dimension of the client area of the hDeviceWindow
1318 * (or the focus window, if hDeviceWindow is NULL) is taken.
1319 **********************/
1321 if (pPresentationParameters->Windowed &&
1322 ((pPresentationParameters->BackBufferWidth == 0) ||
1323 (pPresentationParameters->BackBufferHeight == 0))) {
1325 RECT Rect;
1326 GetClientRect(object->win_handle, &Rect);
1328 if (pPresentationParameters->BackBufferWidth == 0) {
1329 pPresentationParameters->BackBufferWidth = Rect.right;
1330 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1332 if (pPresentationParameters->BackBufferHeight == 0) {
1333 pPresentationParameters->BackBufferHeight = Rect.bottom;
1334 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1338 /* Put the correct figures in the presentation parameters */
1339 TRACE("Copying across presentation parameters\n");
1340 object->presentParms = *pPresentationParameters;
1342 TRACE("calling rendertarget CB\n");
1343 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1344 parent,
1345 object->presentParms.BackBufferWidth,
1346 object->presentParms.BackBufferHeight,
1347 object->presentParms.BackBufferFormat,
1348 object->presentParms.MultiSampleType,
1349 object->presentParms.MultiSampleQuality,
1350 TRUE /* Lockable */,
1351 &object->frontBuffer,
1352 NULL /* pShared (always null)*/);
1353 if (object->frontBuffer != NULL) {
1354 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1355 } else {
1356 ERR("Failed to create the front buffer\n");
1357 goto error;
1361 * Create an opengl context for the display visual
1362 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1363 * use different properties after that point in time. FIXME: How to handle when requested format
1364 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1365 * it chooses is identical to the one already being used!
1366 **********************************/
1367 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1369 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1370 if(!object->context)
1371 return E_OUTOFMEMORY;
1372 object->num_contexts = 1;
1374 ENTER_GL();
1375 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1376 LEAVE_GL();
1378 if (!object->context[0]) {
1379 ERR("Failed to create a new context\n");
1380 hr = WINED3DERR_NOTAVAILABLE;
1381 goto error;
1382 } else {
1383 TRACE("Context created (HWND=%p, glContext=%p)\n",
1384 object->win_handle, object->context[0]->glCtx);
1387 /*********************
1388 * Windowed / Fullscreen
1389 *******************/
1392 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1393 * so we should really check to see if there is a fullscreen swapchain already
1394 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1395 **************************************/
1397 if (!pPresentationParameters->Windowed) {
1399 DEVMODEW devmode;
1400 HDC hdc;
1401 int bpp = 0;
1402 RECT clip_rc;
1404 /* Get info on the current display setup */
1405 hdc = GetDC(0);
1406 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1407 ReleaseDC(0, hdc);
1409 /* Change the display settings */
1410 memset(&devmode, 0, sizeof(devmode));
1411 devmode.dmSize = sizeof(devmode);
1412 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1413 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1414 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1415 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1416 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1418 /* For GetDisplayMode */
1419 This->ddraw_width = devmode.dmPelsWidth;
1420 This->ddraw_height = devmode.dmPelsHeight;
1421 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1423 IWineD3DDevice_SetFullscreen(iface, TRUE);
1425 /* And finally clip mouse to our screen */
1426 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1427 ClipCursor(&clip_rc);
1430 /*********************
1431 * Create the back, front and stencil buffers
1432 *******************/
1433 if(object->presentParms.BackBufferCount > 0) {
1434 int i;
1436 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1437 if(!object->backBuffer) {
1438 ERR("Out of memory\n");
1439 hr = E_OUTOFMEMORY;
1440 goto error;
1443 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1444 TRACE("calling rendertarget CB\n");
1445 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1446 parent,
1447 object->presentParms.BackBufferWidth,
1448 object->presentParms.BackBufferHeight,
1449 object->presentParms.BackBufferFormat,
1450 object->presentParms.MultiSampleType,
1451 object->presentParms.MultiSampleQuality,
1452 TRUE /* Lockable */,
1453 &object->backBuffer[i],
1454 NULL /* pShared (always null)*/);
1455 if(hr == WINED3D_OK && object->backBuffer[i]) {
1456 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1457 } else {
1458 ERR("Cannot create new back buffer\n");
1459 goto error;
1461 ENTER_GL();
1462 glDrawBuffer(GL_BACK);
1463 checkGLcall("glDrawBuffer(GL_BACK)");
1464 LEAVE_GL();
1466 } else {
1467 object->backBuffer = NULL;
1469 /* Single buffering - draw to front buffer */
1470 ENTER_GL();
1471 glDrawBuffer(GL_FRONT);
1472 checkGLcall("glDrawBuffer(GL_FRONT)");
1473 LEAVE_GL();
1476 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1477 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1478 TRACE("Creating depth stencil buffer\n");
1479 if (This->depthStencilBuffer == NULL ) {
1480 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1481 parent,
1482 object->presentParms.BackBufferWidth,
1483 object->presentParms.BackBufferHeight,
1484 object->presentParms.AutoDepthStencilFormat,
1485 object->presentParms.MultiSampleType,
1486 object->presentParms.MultiSampleQuality,
1487 FALSE /* FIXME: Discard */,
1488 &This->depthStencilBuffer,
1489 NULL /* pShared (always null)*/ );
1490 if (This->depthStencilBuffer != NULL)
1491 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1494 /** TODO: A check on width, height and multisample types
1495 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1496 ****************************/
1497 object->wantsDepthStencilBuffer = TRUE;
1498 } else {
1499 object->wantsDepthStencilBuffer = FALSE;
1502 TRACE("Created swapchain %p\n", object);
1503 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1504 return WINED3D_OK;
1506 error:
1507 if (object->backBuffer) {
1508 int i;
1509 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1510 if(object->backBuffer[i]) {
1511 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1512 IUnknown_Release(bufferParent); /* once for the get parent */
1513 if (IUnknown_Release(bufferParent) > 0) {
1514 FIXME("(%p) Something's still holding the back buffer\n",This);
1518 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1519 object->backBuffer = NULL;
1521 if(object->context[0])
1522 DestroyContext(This, object->context[0]);
1523 if(object->frontBuffer) {
1524 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1525 IUnknown_Release(bufferParent); /* once for the get parent */
1526 if (IUnknown_Release(bufferParent) > 0) {
1527 FIXME("(%p) Something's still holding the front buffer\n",This);
1530 HeapFree(GetProcessHeap(), 0, object);
1531 return hr;
1534 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1535 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1537 TRACE("(%p)\n", This);
1539 return This->NumberOfSwapChains;
1542 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1546 if(iSwapChain < This->NumberOfSwapChains) {
1547 *pSwapChain = This->swapchains[iSwapChain];
1548 IWineD3DSwapChain_AddRef(*pSwapChain);
1549 TRACE("(%p) returning %p\n", This, *pSwapChain);
1550 return WINED3D_OK;
1551 } else {
1552 TRACE("Swapchain out of range\n");
1553 *pSwapChain = NULL;
1554 return WINED3DERR_INVALIDCALL;
1558 /*****
1559 * Vertex Declaration
1560 *****/
1561 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1562 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1564 IWineD3DVertexDeclarationImpl *object = NULL;
1565 HRESULT hr = WINED3D_OK;
1567 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1568 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1570 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1572 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1574 return hr;
1577 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1579 unsigned int idx, idx2;
1580 unsigned int offset;
1581 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1582 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1583 BOOL has_blend_idx = has_blend &&
1584 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1585 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1586 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1587 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1588 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1589 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1590 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1592 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1593 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1595 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1596 WINED3DVERTEXELEMENT *elements = NULL;
1598 unsigned int size;
1599 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1600 if (has_blend_idx) num_blends--;
1602 /* Compute declaration size */
1603 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1604 has_psize + has_diffuse + has_specular + num_textures + 1;
1606 /* convert the declaration */
1607 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1608 if (!elements)
1609 return 0;
1611 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1612 idx = 0;
1613 if (has_pos) {
1614 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1615 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1616 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1618 else {
1619 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1620 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1622 elements[idx].UsageIndex = 0;
1623 idx++;
1625 if (has_blend && (num_blends > 0)) {
1626 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1627 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1628 else
1629 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1630 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1631 elements[idx].UsageIndex = 0;
1632 idx++;
1634 if (has_blend_idx) {
1635 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1636 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1637 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1638 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1639 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1640 else
1641 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1642 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1643 elements[idx].UsageIndex = 0;
1644 idx++;
1646 if (has_normal) {
1647 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1648 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1649 elements[idx].UsageIndex = 0;
1650 idx++;
1652 if (has_psize) {
1653 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1654 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1655 elements[idx].UsageIndex = 0;
1656 idx++;
1658 if (has_diffuse) {
1659 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1660 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1661 elements[idx].UsageIndex = 0;
1662 idx++;
1664 if (has_specular) {
1665 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1666 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1667 elements[idx].UsageIndex = 1;
1668 idx++;
1670 for (idx2 = 0; idx2 < num_textures; idx2++) {
1671 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1672 switch (numcoords) {
1673 case WINED3DFVF_TEXTUREFORMAT1:
1674 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1675 break;
1676 case WINED3DFVF_TEXTUREFORMAT2:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT3:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT4:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1684 break;
1686 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1687 elements[idx].UsageIndex = idx2;
1688 idx++;
1691 /* Now compute offsets, and initialize the rest of the fields */
1692 for (idx = 0, offset = 0; idx < size-1; idx++) {
1693 elements[idx].Stream = 0;
1694 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1695 elements[idx].Offset = offset;
1696 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1699 *ppVertexElements = elements;
1700 return size;
1703 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1704 WINED3DVERTEXELEMENT* elements = NULL;
1705 size_t size;
1706 DWORD hr;
1708 size = ConvertFvfToDeclaration(Fvf, &elements);
1709 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1711 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1712 HeapFree(GetProcessHeap(), 0, elements);
1713 if (hr != S_OK) return hr;
1715 return WINED3D_OK;
1718 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1719 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1720 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1721 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1722 HRESULT hr = WINED3D_OK;
1723 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1724 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1726 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1728 if (vertex_declaration) {
1729 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1732 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1734 if (WINED3D_OK != hr) {
1735 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1736 IWineD3DVertexShader_Release(*ppVertexShader);
1737 return WINED3DERR_INVALIDCALL;
1740 return WINED3D_OK;
1743 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1745 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1746 HRESULT hr = WINED3D_OK;
1748 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1749 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1750 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1751 if (WINED3D_OK == hr) {
1752 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1753 } else {
1754 WARN("(%p) : Failed to create pixel shader\n", This);
1757 return hr;
1760 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1762 IWineD3DPaletteImpl *object;
1763 HRESULT hr;
1764 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1766 /* Create the new object */
1767 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1768 if(!object) {
1769 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1770 return E_OUTOFMEMORY;
1773 object->lpVtbl = &IWineD3DPalette_Vtbl;
1774 object->ref = 1;
1775 object->Flags = Flags;
1776 object->parent = Parent;
1777 object->wineD3DDevice = This;
1778 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1780 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1782 if(!object->hpal) {
1783 HeapFree( GetProcessHeap(), 0, object);
1784 return E_OUTOFMEMORY;
1787 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1788 if(FAILED(hr)) {
1789 IWineD3DPalette_Release((IWineD3DPalette *) object);
1790 return hr;
1793 *Palette = (IWineD3DPalette *) object;
1795 return WINED3D_OK;
1798 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1800 IWineD3DSwapChainImpl *swapchain;
1801 HRESULT hr;
1802 DWORD state;
1804 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1805 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1807 /* TODO: Test if OpenGL is compiled in and loaded */
1809 TRACE("(%p) : Creating stateblock\n", This);
1810 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1811 hr = IWineD3DDevice_CreateStateBlock(iface,
1812 WINED3DSBT_INIT,
1813 (IWineD3DStateBlock **)&This->stateBlock,
1814 NULL);
1815 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1816 WARN("Failed to create stateblock\n");
1817 return hr;
1819 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1820 This->updateStateBlock = This->stateBlock;
1821 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1823 hr = allocate_shader_constants(This->updateStateBlock);
1824 if (WINED3D_OK != hr)
1825 return hr;
1827 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1828 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1829 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1831 /* Initialize the texture unit mapping to a 1:1 mapping */
1832 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1833 if (state < GL_LIMITS(fragment_samplers)) {
1834 This->texUnitMap[state] = state;
1835 This->rev_tex_unit_map[state] = state;
1836 } else {
1837 This->texUnitMap[state] = -1;
1838 This->rev_tex_unit_map[state] = -1;
1842 /* Setup the implicit swapchain */
1843 TRACE("Creating implicit swapchain\n");
1844 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1845 if (FAILED(hr) || !swapchain) {
1846 WARN("Failed to create implicit swapchain\n");
1847 return hr;
1850 This->NumberOfSwapChains = 1;
1851 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1852 if(!This->swapchains) {
1853 ERR("Out of memory!\n");
1854 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1855 return E_OUTOFMEMORY;
1857 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1859 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1861 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1862 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1863 This->render_targets[0] = swapchain->backBuffer[0];
1864 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1866 else {
1867 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1868 This->render_targets[0] = swapchain->frontBuffer;
1869 This->lastActiveRenderTarget = swapchain->frontBuffer;
1871 IWineD3DSurface_AddRef(This->render_targets[0]);
1872 This->activeContext = swapchain->context[0];
1873 This->lastThread = GetCurrentThreadId();
1875 /* Depth Stencil support */
1876 This->stencilBufferTarget = This->depthStencilBuffer;
1877 if (NULL != This->stencilBufferTarget) {
1878 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1881 /* Set up some starting GL setup */
1882 ENTER_GL();
1884 /* Setup all the devices defaults */
1885 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1886 #if 0
1887 IWineD3DImpl_CheckGraphicsMemory();
1888 #endif
1890 { /* Set a default viewport */
1891 WINED3DVIEWPORT vp;
1892 vp.X = 0;
1893 vp.Y = 0;
1894 vp.Width = pPresentationParameters->BackBufferWidth;
1895 vp.Height = pPresentationParameters->BackBufferHeight;
1896 vp.MinZ = 0.0f;
1897 vp.MaxZ = 1.0f;
1898 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1901 /* Initialize the current view state */
1902 This->view_ident = 1;
1903 This->contexts[0]->last_was_rhw = 0;
1904 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1905 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1907 switch(wined3d_settings.offscreen_rendering_mode) {
1908 case ORM_FBO:
1909 case ORM_PBUFFER:
1910 This->offscreenBuffer = GL_BACK;
1911 break;
1913 case ORM_BACKBUFFER:
1915 if(GL_LIMITS(aux_buffers) > 0) {
1916 TRACE("Using auxilliary buffer for offscreen rendering\n");
1917 This->offscreenBuffer = GL_AUX0;
1918 } else {
1919 TRACE("Using back buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_BACK;
1925 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1926 LEAVE_GL();
1928 /* Clear the screen */
1929 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1930 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1931 0x00, 1.0, 0);
1933 This->d3d_initialized = TRUE;
1934 return WINED3D_OK;
1937 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1939 int sampler;
1940 UINT i;
1941 TRACE("(%p)\n", This);
1943 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1945 /* I don't think that the interface guarants that the device is destroyed from the same thread
1946 * it was created. Thus make sure a context is active for the glDelete* calls
1948 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1950 TRACE("Deleting high order patches\n");
1951 for(i = 0; i < PATCHMAP_SIZE; i++) {
1952 struct list *e1, *e2;
1953 struct WineD3DRectPatch *patch;
1954 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1955 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1956 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1960 /* Delete the pbuffer context if there is any */
1961 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1963 /* Delete the mouse cursor texture */
1964 if(This->cursorTexture) {
1965 ENTER_GL();
1966 glDeleteTextures(1, &This->cursorTexture);
1967 LEAVE_GL();
1968 This->cursorTexture = 0;
1971 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1972 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1974 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1975 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1978 /* Release the buffers (with sanity checks)*/
1979 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
1980 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
1981 if(This->depthStencilBuffer != This->stencilBufferTarget)
1982 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
1984 This->stencilBufferTarget = NULL;
1986 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
1987 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
1988 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
1990 TRACE("Setting rendertarget to NULL\n");
1991 This->render_targets[0] = NULL;
1993 if (This->depthStencilBuffer) {
1994 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
1995 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
1997 This->depthStencilBuffer = NULL;
2000 for(i=0; i < This->NumberOfSwapChains; i++) {
2001 TRACE("Releasing the implicit swapchain %d\n", i);
2002 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2003 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2007 HeapFree(GetProcessHeap(), 0, This->swapchains);
2008 This->swapchains = NULL;
2009 This->NumberOfSwapChains = 0;
2011 /* Release the update stateblock */
2012 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2013 if(This->updateStateBlock != This->stateBlock)
2014 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2016 This->updateStateBlock = NULL;
2018 { /* because were not doing proper internal refcounts releasing the primary state block
2019 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2020 to set this->stateBlock = NULL; first */
2021 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2022 This->stateBlock = NULL;
2024 /* Release the stateblock */
2025 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2026 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2030 HeapFree(GetProcessHeap(), 0, This->render_targets);
2031 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2032 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2033 This->render_targets = NULL;
2034 This->fbo_color_attachments = NULL;
2035 This->draw_buffers = NULL;
2038 This->d3d_initialized = FALSE;
2039 return WINED3D_OK;
2042 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2044 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2046 /* Setup the window for fullscreen mode */
2047 if(fullscreen && !This->ddraw_fullscreen) {
2048 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2049 } else if(!fullscreen && This->ddraw_fullscreen) {
2050 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2053 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2054 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2055 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2056 * separately.
2058 This->ddraw_fullscreen = fullscreen;
2061 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2062 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2063 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2065 * There is no way to deactivate thread safety once it is enabled
2067 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2070 /*For now just store the flag(needed in case of ddraw) */
2071 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2073 return;
2076 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2077 DEVMODEW devmode;
2078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2079 LONG ret;
2080 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2081 RECT clip_rc;
2083 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2085 /* Resize the screen even without a window:
2086 * The app could have unset it with SetCooperativeLevel, but not called
2087 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2088 * but we don't have any hwnd
2091 memset(&devmode, 0, sizeof(devmode));
2092 devmode.dmSize = sizeof(devmode);
2093 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2094 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2095 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2096 devmode.dmPelsWidth = pMode->Width;
2097 devmode.dmPelsHeight = pMode->Height;
2099 devmode.dmDisplayFrequency = pMode->RefreshRate;
2100 if (pMode->RefreshRate != 0) {
2101 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2104 /* Only change the mode if necessary */
2105 if( (This->ddraw_width == pMode->Width) &&
2106 (This->ddraw_height == pMode->Height) &&
2107 (This->ddraw_format == pMode->Format) &&
2108 (pMode->RefreshRate == 0) ) {
2109 return WINED3D_OK;
2112 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2113 if (ret != DISP_CHANGE_SUCCESSFUL) {
2114 if(devmode.dmDisplayFrequency != 0) {
2115 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2116 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2117 devmode.dmDisplayFrequency = 0;
2118 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2120 if(ret != DISP_CHANGE_SUCCESSFUL) {
2121 return WINED3DERR_NOTAVAILABLE;
2125 /* Store the new values */
2126 This->ddraw_width = pMode->Width;
2127 This->ddraw_height = pMode->Height;
2128 This->ddraw_format = pMode->Format;
2130 /* Only do this with a window of course */
2131 if(This->ddraw_window)
2132 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2134 /* And finally clip mouse to our screen */
2135 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2136 ClipCursor(&clip_rc);
2138 return WINED3D_OK;
2141 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2143 *ppD3D= This->wineD3D;
2144 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2145 IWineD3D_AddRef(*ppD3D);
2146 return WINED3D_OK;
2149 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2150 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2151 * into the video ram as possible and seeing how many fit
2152 * you can also get the correct initial value from nvidia and ATI's driver via X
2153 * texture memory is video memory + AGP memory
2154 *******************/
2155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2156 static BOOL showfixmes = TRUE;
2157 if (showfixmes) {
2158 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2159 (wined3d_settings.emulated_textureram/(1024*1024)),
2160 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2161 showfixmes = FALSE;
2163 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2164 (wined3d_settings.emulated_textureram/(1024*1024)),
2165 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2166 /* return simulated texture memory left */
2167 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2172 /*****
2173 * Get / Set FVF
2174 *****/
2175 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2178 /* Update the current state block */
2179 This->updateStateBlock->changed.fvf = TRUE;
2181 if(This->updateStateBlock->fvf == fvf) {
2182 TRACE("Application is setting the old fvf over, nothing to do\n");
2183 return WINED3D_OK;
2186 This->updateStateBlock->fvf = fvf;
2187 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2189 return WINED3D_OK;
2193 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2195 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2196 *pfvf = This->stateBlock->fvf;
2197 return WINED3D_OK;
2200 /*****
2201 * Get / Set Stream Source
2202 *****/
2203 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2205 IWineD3DVertexBuffer *oldSrc;
2207 if (StreamNumber >= MAX_STREAMS) {
2208 WARN("Stream out of range %d\n", StreamNumber);
2209 return WINED3DERR_INVALIDCALL;
2212 oldSrc = This->stateBlock->streamSource[StreamNumber];
2213 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2215 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2217 if(oldSrc == pStreamData &&
2218 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2219 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2220 TRACE("Application is setting the old values over, nothing to do\n");
2221 return WINED3D_OK;
2224 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2225 if (pStreamData) {
2226 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2227 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2230 /* Handle recording of state blocks */
2231 if (This->isRecordingState) {
2232 TRACE("Recording... not performing anything\n");
2233 return WINED3D_OK;
2236 /* Need to do a getParent and pass the reffs up */
2237 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2238 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2239 so for now, just count internally */
2240 if (pStreamData != NULL) {
2241 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2242 InterlockedIncrement(&vbImpl->bindCount);
2244 if (oldSrc != NULL) {
2245 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2250 return WINED3D_OK;
2253 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2256 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2257 This->stateBlock->streamSource[StreamNumber],
2258 This->stateBlock->streamOffset[StreamNumber],
2259 This->stateBlock->streamStride[StreamNumber]);
2261 if (StreamNumber >= MAX_STREAMS) {
2262 WARN("Stream out of range %d\n", StreamNumber);
2263 return WINED3DERR_INVALIDCALL;
2265 *pStream = This->stateBlock->streamSource[StreamNumber];
2266 *pStride = This->stateBlock->streamStride[StreamNumber];
2267 if (pOffset) {
2268 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2271 if (*pStream != NULL) {
2272 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2274 return WINED3D_OK;
2277 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2279 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2280 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2282 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2283 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2285 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2286 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2288 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2289 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2293 return WINED3D_OK;
2296 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2299 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2300 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2302 TRACE("(%p) : returning %d\n", This, *Divider);
2304 return WINED3D_OK;
2307 /*****
2308 * Get / Set & Multiply Transform
2309 *****/
2310 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2313 /* Most of this routine, comments included copied from ddraw tree initially: */
2314 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2316 /* Handle recording of state blocks */
2317 if (This->isRecordingState) {
2318 TRACE("Recording... not performing anything\n");
2319 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2320 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2321 return WINED3D_OK;
2325 * If the new matrix is the same as the current one,
2326 * we cut off any further processing. this seems to be a reasonable
2327 * optimization because as was noticed, some apps (warcraft3 for example)
2328 * tend towards setting the same matrix repeatedly for some reason.
2330 * From here on we assume that the new matrix is different, wherever it matters.
2332 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2333 TRACE("The app is setting the same matrix over again\n");
2334 return WINED3D_OK;
2335 } else {
2336 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2340 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2341 where ViewMat = Camera space, WorldMat = world space.
2343 In OpenGL, camera and world space is combined into GL_MODELVIEW
2344 matrix. The Projection matrix stay projection matrix.
2347 /* Capture the times we can just ignore the change for now */
2348 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2349 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2350 /* Handled by the state manager */
2353 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2354 return WINED3D_OK;
2357 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2359 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2360 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2361 return WINED3D_OK;
2364 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2365 WINED3DMATRIX *mat = NULL;
2366 WINED3DMATRIX temp;
2368 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2369 * below means it will be recorded in a state block change, but it
2370 * works regardless where it is recorded.
2371 * If this is found to be wrong, change to StateBlock.
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2374 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2376 if (State < HIGHEST_TRANSFORMSTATE)
2378 mat = &This->updateStateBlock->transforms[State];
2379 } else {
2380 FIXME("Unhandled transform state!!\n");
2383 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2385 /* Apply change via set transform - will reapply to eg. lights this way */
2386 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2389 /*****
2390 * Get / Set Light
2391 *****/
2392 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2393 you can reference any indexes you want as long as that number max are enabled at any
2394 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2395 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2396 but when recording, just build a chain pretty much of commands to be replayed. */
2398 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2399 float rho;
2400 PLIGHTINFOEL *object = NULL;
2401 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2402 struct list *e;
2404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2405 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2407 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2408 * the gl driver.
2410 if(!pLight) {
2411 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2412 return WINED3DERR_INVALIDCALL;
2415 switch(pLight->Type) {
2416 case WINED3DLIGHT_POINT:
2417 case WINED3DLIGHT_SPOT:
2418 case WINED3DLIGHT_PARALLELPOINT:
2419 case WINED3DLIGHT_GLSPOT:
2420 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2421 * most wanted
2423 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2424 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2425 return WINED3DERR_INVALIDCALL;
2427 break;
2429 case WINED3DLIGHT_DIRECTIONAL:
2430 /* Ignores attenuation */
2431 break;
2433 default:
2434 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2435 return WINED3DERR_INVALIDCALL;
2438 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2439 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2440 if(object->OriginalIndex == Index) break;
2441 object = NULL;
2444 if(!object) {
2445 TRACE("Adding new light\n");
2446 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2447 if(!object) {
2448 ERR("Out of memory error when allocating a light\n");
2449 return E_OUTOFMEMORY;
2451 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2452 object->glIndex = -1;
2453 object->OriginalIndex = Index;
2454 object->changed = TRUE;
2457 /* Initialize the object */
2458 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,
2459 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2460 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2461 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2462 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2463 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2464 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2466 /* Save away the information */
2467 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2469 switch (pLight->Type) {
2470 case WINED3DLIGHT_POINT:
2471 /* Position */
2472 object->lightPosn[0] = pLight->Position.x;
2473 object->lightPosn[1] = pLight->Position.y;
2474 object->lightPosn[2] = pLight->Position.z;
2475 object->lightPosn[3] = 1.0f;
2476 object->cutoff = 180.0f;
2477 /* FIXME: Range */
2478 break;
2480 case WINED3DLIGHT_DIRECTIONAL:
2481 /* Direction */
2482 object->lightPosn[0] = -pLight->Direction.x;
2483 object->lightPosn[1] = -pLight->Direction.y;
2484 object->lightPosn[2] = -pLight->Direction.z;
2485 object->lightPosn[3] = 0.0;
2486 object->exponent = 0.0f;
2487 object->cutoff = 180.0f;
2488 break;
2490 case WINED3DLIGHT_SPOT:
2491 /* Position */
2492 object->lightPosn[0] = pLight->Position.x;
2493 object->lightPosn[1] = pLight->Position.y;
2494 object->lightPosn[2] = pLight->Position.z;
2495 object->lightPosn[3] = 1.0;
2497 /* Direction */
2498 object->lightDirn[0] = pLight->Direction.x;
2499 object->lightDirn[1] = pLight->Direction.y;
2500 object->lightDirn[2] = pLight->Direction.z;
2501 object->lightDirn[3] = 1.0;
2504 * opengl-ish and d3d-ish spot lights use too different models for the
2505 * light "intensity" as a function of the angle towards the main light direction,
2506 * so we only can approximate very roughly.
2507 * however spot lights are rather rarely used in games (if ever used at all).
2508 * furthermore if still used, probably nobody pays attention to such details.
2510 if (pLight->Falloff == 0) {
2511 rho = 6.28f;
2512 } else {
2513 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2515 if (rho < 0.0001) rho = 0.0001f;
2516 object->exponent = -0.3/log(cos(rho/2));
2517 if (object->exponent > 128.0) {
2518 object->exponent = 128.0;
2520 object->cutoff = pLight->Phi*90/M_PI;
2522 /* FIXME: Range */
2523 break;
2525 default:
2526 FIXME("Unrecognized light type %d\n", pLight->Type);
2529 /* Update the live definitions if the light is currently assigned a glIndex */
2530 if (object->glIndex != -1 && !This->isRecordingState) {
2531 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2533 return WINED3D_OK;
2536 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2537 PLIGHTINFOEL *lightInfo = NULL;
2538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2539 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2540 struct list *e;
2541 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2543 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2544 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2545 if(lightInfo->OriginalIndex == Index) break;
2546 lightInfo = NULL;
2549 if (lightInfo == NULL) {
2550 TRACE("Light information requested but light not defined\n");
2551 return WINED3DERR_INVALIDCALL;
2554 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2555 return WINED3D_OK;
2558 /*****
2559 * Get / Set Light Enable
2560 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2561 *****/
2562 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2563 PLIGHTINFOEL *lightInfo = NULL;
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2566 struct list *e;
2567 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2569 /* Tests show true = 128...not clear why */
2570 Enable = Enable? 128: 0;
2572 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2573 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2574 if(lightInfo->OriginalIndex == Index) break;
2575 lightInfo = NULL;
2577 TRACE("Found light: %p\n", lightInfo);
2579 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2580 if (lightInfo == NULL) {
2582 TRACE("Light enabled requested but light not defined, so defining one!\n");
2583 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2585 /* Search for it again! Should be fairly quick as near head of list */
2586 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2587 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2588 if(lightInfo->OriginalIndex == Index) break;
2589 lightInfo = NULL;
2591 if (lightInfo == NULL) {
2592 FIXME("Adding default lights has failed dismally\n");
2593 return WINED3DERR_INVALIDCALL;
2597 lightInfo->enabledChanged = TRUE;
2598 if(!Enable) {
2599 if(lightInfo->glIndex != -1) {
2600 if(!This->isRecordingState) {
2601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2604 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2605 lightInfo->glIndex = -1;
2606 } else {
2607 TRACE("Light already disabled, nothing to do\n");
2609 } else {
2610 if (lightInfo->glIndex != -1) {
2611 /* nop */
2612 TRACE("Nothing to do as light was enabled\n");
2613 } else {
2614 int i;
2615 /* Find a free gl light */
2616 for(i = 0; i < This->maxConcurrentLights; i++) {
2617 if(This->stateBlock->activeLights[i] == NULL) {
2618 This->stateBlock->activeLights[i] = lightInfo;
2619 lightInfo->glIndex = i;
2620 break;
2623 if(lightInfo->glIndex == -1) {
2624 ERR("Too many concurrently active lights\n");
2625 return WINED3DERR_INVALIDCALL;
2628 /* i == lightInfo->glIndex */
2629 if(!This->isRecordingState) {
2630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2635 return WINED3D_OK;
2638 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2640 PLIGHTINFOEL *lightInfo = NULL;
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2642 struct list *e;
2643 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2644 TRACE("(%p) : for idx(%d)\n", This, Index);
2646 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2647 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2648 if(lightInfo->OriginalIndex == Index) break;
2649 lightInfo = NULL;
2652 if (lightInfo == NULL) {
2653 TRACE("Light enabled state requested but light not defined\n");
2654 return WINED3DERR_INVALIDCALL;
2656 /* true is 128 according to SetLightEnable */
2657 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2658 return WINED3D_OK;
2661 /*****
2662 * Get / Set Clip Planes
2663 *****/
2664 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2666 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2668 /* Validate Index */
2669 if (Index >= GL_LIMITS(clipplanes)) {
2670 TRACE("Application has requested clipplane this device doesn't support\n");
2671 return WINED3DERR_INVALIDCALL;
2674 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2676 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2677 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2678 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2679 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2680 TRACE("Application is setting old values over, nothing to do\n");
2681 return WINED3D_OK;
2684 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2685 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2686 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2687 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2689 /* Handle recording of state blocks */
2690 if (This->isRecordingState) {
2691 TRACE("Recording... not performing anything\n");
2692 return WINED3D_OK;
2695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2697 return WINED3D_OK;
2700 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2701 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2702 TRACE("(%p) : for idx %d\n", This, Index);
2704 /* Validate Index */
2705 if (Index >= GL_LIMITS(clipplanes)) {
2706 TRACE("Application has requested clipplane this device doesn't support\n");
2707 return WINED3DERR_INVALIDCALL;
2710 pPlane[0] = This->stateBlock->clipplane[Index][0];
2711 pPlane[1] = This->stateBlock->clipplane[Index][1];
2712 pPlane[2] = This->stateBlock->clipplane[Index][2];
2713 pPlane[3] = This->stateBlock->clipplane[Index][3];
2714 return WINED3D_OK;
2717 /*****
2718 * Get / Set Clip Plane Status
2719 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2720 *****/
2721 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2723 FIXME("(%p) : stub\n", This);
2724 if (NULL == pClipStatus) {
2725 return WINED3DERR_INVALIDCALL;
2727 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2728 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2729 return WINED3D_OK;
2732 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 FIXME("(%p) : stub\n", This);
2735 if (NULL == pClipStatus) {
2736 return WINED3DERR_INVALIDCALL;
2738 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2739 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2740 return WINED3D_OK;
2743 /*****
2744 * Get / Set Material
2745 *****/
2746 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2749 This->updateStateBlock->changed.material = TRUE;
2750 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2752 /* Handle recording of state blocks */
2753 if (This->isRecordingState) {
2754 TRACE("Recording... not performing anything\n");
2755 return WINED3D_OK;
2758 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2759 return WINED3D_OK;
2762 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2764 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2765 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2766 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2767 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2768 pMaterial->Ambient.b, pMaterial->Ambient.a);
2769 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2770 pMaterial->Specular.b, pMaterial->Specular.a);
2771 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2772 pMaterial->Emissive.b, pMaterial->Emissive.a);
2773 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2775 return WINED3D_OK;
2778 /*****
2779 * Get / Set Indices
2780 *****/
2781 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2783 IWineD3DIndexBuffer *oldIdxs;
2785 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2786 oldIdxs = This->updateStateBlock->pIndexData;
2788 This->updateStateBlock->changed.indices = TRUE;
2789 This->updateStateBlock->pIndexData = pIndexData;
2791 /* Handle recording of state blocks */
2792 if (This->isRecordingState) {
2793 TRACE("Recording... not performing anything\n");
2794 return WINED3D_OK;
2797 if(oldIdxs != pIndexData) {
2798 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2800 return WINED3D_OK;
2803 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2806 *ppIndexData = This->stateBlock->pIndexData;
2808 /* up ref count on ppindexdata */
2809 if (*ppIndexData) {
2810 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2811 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2812 }else{
2813 TRACE("(%p) No index data set\n", This);
2815 TRACE("Returning %p\n", *ppIndexData);
2817 return WINED3D_OK;
2820 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2821 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2823 TRACE("(%p)->(%d)\n", This, BaseIndex);
2825 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2826 TRACE("Application is setting the old value over, nothing to do\n");
2827 return WINED3D_OK;
2830 This->updateStateBlock->baseVertexIndex = BaseIndex;
2832 if (This->isRecordingState) {
2833 TRACE("Recording... not performing anything\n");
2834 return WINED3D_OK;
2836 /* The base vertex index affects the stream sources */
2837 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2838 return WINED3D_OK;
2841 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2843 TRACE("(%p) : base_index %p\n", This, base_index);
2845 *base_index = This->stateBlock->baseVertexIndex;
2847 TRACE("Returning %u\n", *base_index);
2849 return WINED3D_OK;
2852 /*****
2853 * Get / Set Viewports
2854 *****/
2855 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2856 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2858 TRACE("(%p)\n", This);
2859 This->updateStateBlock->changed.viewport = TRUE;
2860 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2862 /* Handle recording of state blocks */
2863 if (This->isRecordingState) {
2864 TRACE("Recording... not performing anything\n");
2865 return WINED3D_OK;
2868 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2869 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2872 return WINED3D_OK;
2876 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 TRACE("(%p)\n", This);
2879 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2880 return WINED3D_OK;
2883 /*****
2884 * Get / Set Render States
2885 * TODO: Verify against dx9 definitions
2886 *****/
2887 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 DWORD oldValue = This->stateBlock->renderState[State];
2892 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2894 This->updateStateBlock->changed.renderState[State] = TRUE;
2895 This->updateStateBlock->renderState[State] = Value;
2897 /* Handle recording of state blocks */
2898 if (This->isRecordingState) {
2899 TRACE("Recording... not performing anything\n");
2900 return WINED3D_OK;
2903 /* Compared here and not before the assignment to allow proper stateblock recording */
2904 if(Value == oldValue) {
2905 TRACE("Application is setting the old value over, nothing to do\n");
2906 } else {
2907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2910 return WINED3D_OK;
2913 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2916 *pValue = This->stateBlock->renderState[State];
2917 return WINED3D_OK;
2920 /*****
2921 * Get / Set Sampler States
2922 * TODO: Verify against dx9 definitions
2923 *****/
2925 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2927 DWORD oldValue;
2929 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2930 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2932 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2933 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2937 * SetSampler is designed to allow for more than the standard up to 8 textures
2938 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2939 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2941 * http://developer.nvidia.com/object/General_FAQ.html#t6
2943 * There are two new settings for GForce
2944 * the sampler one:
2945 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2946 * and the texture one:
2947 * GL_MAX_TEXTURE_COORDS_ARB.
2948 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2949 ******************/
2951 oldValue = This->stateBlock->samplerState[Sampler][Type];
2952 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2953 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2955 /* Handle recording of state blocks */
2956 if (This->isRecordingState) {
2957 TRACE("Recording... not performing anything\n");
2958 return WINED3D_OK;
2961 if(oldValue == Value) {
2962 TRACE("Application is setting the old value over, nothing to do\n");
2963 return WINED3D_OK;
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2968 return WINED3D_OK;
2971 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2974 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2975 This, Sampler, debug_d3dsamplerstate(Type), Type);
2977 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2978 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2981 *Value = This->stateBlock->samplerState[Sampler][Type];
2982 TRACE("(%p) : Returning %#x\n", This, *Value);
2984 return WINED3D_OK;
2987 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2990 This->updateStateBlock->changed.scissorRect = TRUE;
2991 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2992 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2993 return WINED3D_OK;
2995 CopyRect(&This->updateStateBlock->scissorRect, pRect);
2997 if(This->isRecordingState) {
2998 TRACE("Recording... not performing anything\n");
2999 return WINED3D_OK;
3002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3004 return WINED3D_OK;
3007 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3011 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3012 return WINED3D_OK;
3015 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3017 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3019 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3021 This->updateStateBlock->vertexDecl = pDecl;
3022 This->updateStateBlock->changed.vertexDecl = TRUE;
3024 if (This->isRecordingState) {
3025 TRACE("Recording... not performing anything\n");
3026 return WINED3D_OK;
3027 } else if(pDecl == oldDecl) {
3028 /* Checked after the assignment to allow proper stateblock recording */
3029 TRACE("Application is setting the old declaration over, nothing to do\n");
3030 return WINED3D_OK;
3033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3034 return WINED3D_OK;
3037 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3042 *ppDecl = This->stateBlock->vertexDecl;
3043 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3044 return WINED3D_OK;
3047 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3051 This->updateStateBlock->vertexShader = pShader;
3052 This->updateStateBlock->changed.vertexShader = TRUE;
3054 if (This->isRecordingState) {
3055 TRACE("Recording... not performing anything\n");
3056 return WINED3D_OK;
3057 } else if(oldShader == pShader) {
3058 /* Checked here to allow proper stateblock recording */
3059 TRACE("App is setting the old shader over, nothing to do\n");
3060 return WINED3D_OK;
3063 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3065 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3067 return WINED3D_OK;
3070 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3073 if (NULL == ppShader) {
3074 return WINED3DERR_INVALIDCALL;
3076 *ppShader = This->stateBlock->vertexShader;
3077 if( NULL != *ppShader)
3078 IWineD3DVertexShader_AddRef(*ppShader);
3080 TRACE("(%p) : returning %p\n", This, *ppShader);
3081 return WINED3D_OK;
3084 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3085 IWineD3DDevice *iface,
3086 UINT start,
3087 CONST BOOL *srcData,
3088 UINT count) {
3090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3091 int i, cnt = min(count, MAX_CONST_B - start);
3093 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3094 iface, srcData, start, count);
3096 if (srcData == NULL || cnt < 0)
3097 return WINED3DERR_INVALIDCALL;
3099 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3100 for (i = 0; i < cnt; i++)
3101 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3103 for (i = start; i < cnt + start; ++i) {
3104 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3107 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3109 return WINED3D_OK;
3112 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3113 IWineD3DDevice *iface,
3114 UINT start,
3115 BOOL *dstData,
3116 UINT count) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3119 int cnt = min(count, MAX_CONST_B - start);
3121 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3122 iface, dstData, start, count);
3124 if (dstData == NULL || cnt < 0)
3125 return WINED3DERR_INVALIDCALL;
3127 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3128 return WINED3D_OK;
3131 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3132 IWineD3DDevice *iface,
3133 UINT start,
3134 CONST int *srcData,
3135 UINT count) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 int i, cnt = min(count, MAX_CONST_I - start);
3140 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3141 iface, srcData, start, count);
3143 if (srcData == NULL || cnt < 0)
3144 return WINED3DERR_INVALIDCALL;
3146 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3147 for (i = 0; i < cnt; i++)
3148 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3149 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3151 for (i = start; i < cnt + start; ++i) {
3152 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3161 IWineD3DDevice *iface,
3162 UINT start,
3163 int *dstData,
3164 UINT count) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3167 int cnt = min(count, MAX_CONST_I - start);
3169 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3170 iface, dstData, start, count);
3172 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3173 return WINED3DERR_INVALIDCALL;
3175 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3176 return WINED3D_OK;
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3180 IWineD3DDevice *iface,
3181 UINT start,
3182 CONST float *srcData,
3183 UINT count) {
3185 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3186 int i;
3188 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3189 iface, srcData, start, count);
3191 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3192 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3193 return WINED3DERR_INVALIDCALL;
3195 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3196 if(TRACE_ON(d3d)) {
3197 for (i = 0; i < count; i++)
3198 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3199 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3202 for (i = start; i < count + start; ++i) {
3203 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3204 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3205 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3206 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3207 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3209 ptr->idx[ptr->count++] = i;
3210 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3216 return WINED3D_OK;
3219 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3220 IWineD3DDevice *iface,
3221 UINT start,
3222 float *dstData,
3223 UINT count) {
3225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3226 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3228 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3229 iface, dstData, start, count);
3231 if (dstData == NULL || cnt < 0)
3232 return WINED3DERR_INVALIDCALL;
3234 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3235 return WINED3D_OK;
3238 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3239 DWORD i;
3240 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3245 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3246 int i = This->rev_tex_unit_map[unit];
3247 int j = This->texUnitMap[stage];
3249 This->texUnitMap[stage] = unit;
3250 if (i != -1 && i != stage) {
3251 This->texUnitMap[i] = -1;
3254 This->rev_tex_unit_map[unit] = stage;
3255 if (j != -1 && j != unit) {
3256 This->rev_tex_unit_map[j] = -1;
3260 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3261 int i;
3263 for (i = 0; i < MAX_TEXTURES; ++i) {
3264 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3265 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3266 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3267 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3268 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3269 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3270 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3271 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3273 if (color_op == WINED3DTOP_DISABLE) {
3274 /* Not used, and disable higher stages */
3275 while (i < MAX_TEXTURES) {
3276 This->fixed_function_usage_map[i] = FALSE;
3277 ++i;
3279 break;
3282 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3283 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3284 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3285 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3286 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3287 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3288 This->fixed_function_usage_map[i] = TRUE;
3289 } else {
3290 This->fixed_function_usage_map[i] = FALSE;
3293 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3294 This->fixed_function_usage_map[i+1] = TRUE;
3299 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3300 int i, tex;
3302 device_update_fixed_function_usage_map(This);
3304 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3305 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3306 if (!This->fixed_function_usage_map[i]) continue;
3308 if (This->texUnitMap[i] != i) {
3309 device_map_stage(This, i, i);
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3311 markTextureStagesDirty(This, i);
3314 return;
3317 /* Now work out the mapping */
3318 tex = 0;
3319 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3320 if (!This->fixed_function_usage_map[i]) continue;
3322 if (This->texUnitMap[i] != tex) {
3323 device_map_stage(This, i, tex);
3324 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3325 markTextureStagesDirty(This, i);
3328 ++tex;
3332 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3333 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3334 int i;
3336 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3337 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3338 device_map_stage(This, i, i);
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3340 if (i < MAX_TEXTURES) {
3341 markTextureStagesDirty(This, i);
3347 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3348 int current_mapping = This->rev_tex_unit_map[unit];
3350 if (current_mapping == -1) {
3351 /* Not currently used */
3352 return TRUE;
3355 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3356 /* Used by a fragment sampler */
3358 if (!pshader_sampler_tokens) {
3359 /* No pixel shader, check fixed function */
3360 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3363 /* Pixel shader, check the shader's sampler map */
3364 return !pshader_sampler_tokens[current_mapping];
3367 /* Used by a vertex sampler */
3368 return !vshader_sampler_tokens[current_mapping];
3371 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3372 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3373 DWORD *pshader_sampler_tokens = NULL;
3374 int start = GL_LIMITS(combined_samplers) - 1;
3375 int i;
3377 if (ps) {
3378 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3380 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3381 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3382 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3385 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3386 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3387 if (vshader_sampler_tokens[i]) {
3388 if (This->texUnitMap[vsampler_idx] != -1) {
3389 /* Already mapped somewhere */
3390 continue;
3393 while (start >= 0) {
3394 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3395 device_map_stage(This, vsampler_idx, start);
3396 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3398 --start;
3399 break;
3402 --start;
3408 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3409 BOOL vs = use_vs(This);
3410 BOOL ps = use_ps(This);
3412 * Rules are:
3413 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3414 * that would be really messy and require shader recompilation
3415 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3416 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3418 if (ps) {
3419 device_map_psamplers(This);
3420 } else {
3421 device_map_fixed_function_samplers(This);
3424 if (vs) {
3425 device_map_vsamplers(This, ps);
3429 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3432 This->updateStateBlock->pixelShader = pShader;
3433 This->updateStateBlock->changed.pixelShader = TRUE;
3435 /* Handle recording of state blocks */
3436 if (This->isRecordingState) {
3437 TRACE("Recording... not performing anything\n");
3440 if (This->isRecordingState) {
3441 TRACE("Recording... not performing anything\n");
3442 return WINED3D_OK;
3445 if(pShader == oldShader) {
3446 TRACE("App is setting the old pixel shader over, nothing to do\n");
3447 return WINED3D_OK;
3450 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3453 return WINED3D_OK;
3456 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3459 if (NULL == ppShader) {
3460 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3461 return WINED3DERR_INVALIDCALL;
3464 *ppShader = This->stateBlock->pixelShader;
3465 if (NULL != *ppShader) {
3466 IWineD3DPixelShader_AddRef(*ppShader);
3468 TRACE("(%p) : returning %p\n", This, *ppShader);
3469 return WINED3D_OK;
3472 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3473 IWineD3DDevice *iface,
3474 UINT start,
3475 CONST BOOL *srcData,
3476 UINT count) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3479 int i, cnt = min(count, MAX_CONST_B - start);
3481 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3482 iface, srcData, start, count);
3484 if (srcData == NULL || cnt < 0)
3485 return WINED3DERR_INVALIDCALL;
3487 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3488 for (i = 0; i < cnt; i++)
3489 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3491 for (i = start; i < cnt + start; ++i) {
3492 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3495 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3497 return WINED3D_OK;
3500 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3501 IWineD3DDevice *iface,
3502 UINT start,
3503 BOOL *dstData,
3504 UINT count) {
3506 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3507 int cnt = min(count, MAX_CONST_B - start);
3509 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3510 iface, dstData, start, count);
3512 if (dstData == NULL || cnt < 0)
3513 return WINED3DERR_INVALIDCALL;
3515 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3516 return WINED3D_OK;
3519 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3520 IWineD3DDevice *iface,
3521 UINT start,
3522 CONST int *srcData,
3523 UINT count) {
3525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3526 int i, cnt = min(count, MAX_CONST_I - start);
3528 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3529 iface, srcData, start, count);
3531 if (srcData == NULL || cnt < 0)
3532 return WINED3DERR_INVALIDCALL;
3534 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3535 for (i = 0; i < cnt; i++)
3536 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3537 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3539 for (i = start; i < cnt + start; ++i) {
3540 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3545 return WINED3D_OK;
3548 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3549 IWineD3DDevice *iface,
3550 UINT start,
3551 int *dstData,
3552 UINT count) {
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555 int cnt = min(count, MAX_CONST_I - start);
3557 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3558 iface, dstData, start, count);
3560 if (dstData == NULL || cnt < 0)
3561 return WINED3DERR_INVALIDCALL;
3563 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3564 return WINED3D_OK;
3567 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3568 IWineD3DDevice *iface,
3569 UINT start,
3570 CONST float *srcData,
3571 UINT count) {
3573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3574 int i;
3576 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3577 iface, srcData, start, count);
3579 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3580 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3581 return WINED3DERR_INVALIDCALL;
3583 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3584 if(TRACE_ON(d3d)) {
3585 for (i = 0; i < count; i++)
3586 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3587 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3590 for (i = start; i < count + start; ++i) {
3591 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3592 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3593 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3594 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3595 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3597 ptr->idx[ptr->count++] = i;
3598 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3604 return WINED3D_OK;
3607 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3608 IWineD3DDevice *iface,
3609 UINT start,
3610 float *dstData,
3611 UINT count) {
3613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3614 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3616 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3617 iface, dstData, start, count);
3619 if (dstData == NULL || cnt < 0)
3620 return WINED3DERR_INVALIDCALL;
3622 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3623 return WINED3D_OK;
3626 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3627 static HRESULT
3628 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3629 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3630 unsigned int i;
3631 DWORD DestFVF = dest->fvf;
3632 WINED3DVIEWPORT vp;
3633 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3634 BOOL doClip;
3635 int numTextures;
3637 if (lpStrideData->u.s.normal.lpData) {
3638 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3641 if (lpStrideData->u.s.position.lpData == NULL) {
3642 ERR("Source has no position mask\n");
3643 return WINED3DERR_INVALIDCALL;
3646 /* We might access VBOs from this code, so hold the lock */
3647 ENTER_GL();
3649 if (dest->resource.allocatedMemory == NULL) {
3650 /* This may happen if we do direct locking into a vbo. Unlikely,
3651 * but theoretically possible(ddraw processvertices test)
3653 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3654 if(!dest->resource.allocatedMemory) {
3655 LEAVE_GL();
3656 ERR("Out of memory\n");
3657 return E_OUTOFMEMORY;
3659 if(dest->vbo) {
3660 void *src;
3661 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3662 checkGLcall("glBindBufferARB");
3663 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3664 if(src) {
3665 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3667 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3668 checkGLcall("glUnmapBufferARB");
3672 /* Get a pointer into the destination vbo(create one if none exists) and
3673 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3675 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3676 CreateVBO(dest);
3679 if(dest->vbo) {
3680 unsigned char extrabytes = 0;
3681 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3682 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3683 * this may write 4 extra bytes beyond the area that should be written
3685 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3686 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3687 if(!dest_conv_addr) {
3688 ERR("Out of memory\n");
3689 /* Continue without storing converted vertices */
3691 dest_conv = dest_conv_addr;
3694 /* Should I clip?
3695 * a) WINED3DRS_CLIPPING is enabled
3696 * b) WINED3DVOP_CLIP is passed
3698 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3699 static BOOL warned = FALSE;
3701 * The clipping code is not quite correct. Some things need
3702 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3703 * so disable clipping for now.
3704 * (The graphics in Half-Life are broken, and my processvertices
3705 * test crashes with IDirect3DDevice3)
3706 doClip = TRUE;
3708 doClip = FALSE;
3709 if(!warned) {
3710 warned = TRUE;
3711 FIXME("Clipping is broken and disabled for now\n");
3713 } else doClip = FALSE;
3714 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3716 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3717 WINED3DTS_VIEW,
3718 &view_mat);
3719 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3720 WINED3DTS_PROJECTION,
3721 &proj_mat);
3722 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3723 WINED3DTS_WORLDMATRIX(0),
3724 &world_mat);
3726 TRACE("View mat:\n");
3727 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);
3728 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);
3729 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);
3730 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);
3732 TRACE("Proj mat:\n");
3733 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);
3734 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);
3735 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);
3736 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);
3738 TRACE("World mat:\n");
3739 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);
3740 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);
3741 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);
3742 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);
3744 /* Get the viewport */
3745 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3746 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3747 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3749 multiply_matrix(&mat,&view_mat,&world_mat);
3750 multiply_matrix(&mat,&proj_mat,&mat);
3752 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3754 for (i = 0; i < dwCount; i+= 1) {
3755 unsigned int tex_index;
3757 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3758 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3759 /* The position first */
3760 float *p =
3761 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3762 float x, y, z, rhw;
3763 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3765 /* Multiplication with world, view and projection matrix */
3766 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);
3767 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);
3768 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);
3769 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);
3771 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3773 /* WARNING: The following things are taken from d3d7 and were not yet checked
3774 * against d3d8 or d3d9!
3777 /* Clipping conditions: From
3778 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3780 * A vertex is clipped if it does not match the following requirements
3781 * -rhw < x <= rhw
3782 * -rhw < y <= rhw
3783 * 0 < z <= rhw
3784 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3786 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3787 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3791 if( !doClip ||
3792 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3793 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3794 ( rhw > eps ) ) ) {
3796 /* "Normal" viewport transformation (not clipped)
3797 * 1) The values are divided by rhw
3798 * 2) The y axis is negative, so multiply it with -1
3799 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3800 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3801 * 4) Multiply x with Width/2 and add Width/2
3802 * 5) The same for the height
3803 * 6) Add the viewpoint X and Y to the 2D coordinates and
3804 * The minimum Z value to z
3805 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3807 * Well, basically it's simply a linear transformation into viewport
3808 * coordinates
3811 x /= rhw;
3812 y /= rhw;
3813 z /= rhw;
3815 y *= -1;
3817 x *= vp.Width / 2;
3818 y *= vp.Height / 2;
3819 z *= vp.MaxZ - vp.MinZ;
3821 x += vp.Width / 2 + vp.X;
3822 y += vp.Height / 2 + vp.Y;
3823 z += vp.MinZ;
3825 rhw = 1 / rhw;
3826 } else {
3827 /* That vertex got clipped
3828 * Contrary to OpenGL it is not dropped completely, it just
3829 * undergoes a different calculation.
3831 TRACE("Vertex got clipped\n");
3832 x += rhw;
3833 y += rhw;
3835 x /= 2;
3836 y /= 2;
3838 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3839 * outside of the main vertex buffer memory. That needs some more
3840 * investigation...
3844 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3847 ( (float *) dest_ptr)[0] = x;
3848 ( (float *) dest_ptr)[1] = y;
3849 ( (float *) dest_ptr)[2] = z;
3850 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3852 dest_ptr += 3 * sizeof(float);
3854 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3855 dest_ptr += sizeof(float);
3858 if(dest_conv) {
3859 float w = 1 / rhw;
3860 ( (float *) dest_conv)[0] = x * w;
3861 ( (float *) dest_conv)[1] = y * w;
3862 ( (float *) dest_conv)[2] = z * w;
3863 ( (float *) dest_conv)[3] = w;
3865 dest_conv += 3 * sizeof(float);
3867 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3868 dest_conv += sizeof(float);
3872 if (DestFVF & WINED3DFVF_PSIZE) {
3873 dest_ptr += sizeof(DWORD);
3874 if(dest_conv) dest_conv += sizeof(DWORD);
3876 if (DestFVF & WINED3DFVF_NORMAL) {
3877 float *normal =
3878 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3879 /* AFAIK this should go into the lighting information */
3880 FIXME("Didn't expect the destination to have a normal\n");
3881 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3882 if(dest_conv) {
3883 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3887 if (DestFVF & WINED3DFVF_DIFFUSE) {
3888 DWORD *color_d =
3889 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3890 if(!color_d) {
3891 static BOOL warned = FALSE;
3893 if(!warned) {
3894 ERR("No diffuse color in source, but destination has one\n");
3895 warned = TRUE;
3898 *( (DWORD *) dest_ptr) = 0xffffffff;
3899 dest_ptr += sizeof(DWORD);
3901 if(dest_conv) {
3902 *( (DWORD *) dest_conv) = 0xffffffff;
3903 dest_conv += sizeof(DWORD);
3906 else {
3907 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3908 if(dest_conv) {
3909 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3910 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3911 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3912 dest_conv += sizeof(DWORD);
3917 if (DestFVF & WINED3DFVF_SPECULAR) {
3918 /* What's the color value in the feedback buffer? */
3919 DWORD *color_s =
3920 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3921 if(!color_s) {
3922 static BOOL warned = FALSE;
3924 if(!warned) {
3925 ERR("No specular color in source, but destination has one\n");
3926 warned = TRUE;
3929 *( (DWORD *) dest_ptr) = 0xFF000000;
3930 dest_ptr += sizeof(DWORD);
3932 if(dest_conv) {
3933 *( (DWORD *) dest_conv) = 0xFF000000;
3934 dest_conv += sizeof(DWORD);
3937 else {
3938 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3939 if(dest_conv) {
3940 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3941 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3942 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3943 dest_conv += sizeof(DWORD);
3948 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3949 float *tex_coord =
3950 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3951 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3952 if(!tex_coord) {
3953 ERR("No source texture, but destination requests one\n");
3954 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3955 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3957 else {
3958 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3959 if(dest_conv) {
3960 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3966 if(dest_conv) {
3967 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3968 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3969 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3970 dwCount * get_flexible_vertex_size(DestFVF),
3971 dest_conv_addr));
3972 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3973 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3976 LEAVE_GL();
3978 return WINED3D_OK;
3980 #undef copy_and_next
3982 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3984 WineDirect3DVertexStridedData strided;
3985 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3986 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3988 if(pVertexDecl) {
3989 ERR("Output vertex declaration not implemented yet\n");
3992 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3993 * and this call is quite performance critical, so don't call needlessly
3995 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
3996 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
3999 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4000 * control the streamIsUP flag, thus restore it afterwards.
4002 This->stateBlock->streamIsUP = FALSE;
4003 memset(&strided, 0, sizeof(strided));
4004 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4005 This->stateBlock->streamIsUP = streamWasUP;
4007 if(vbo || SrcStartIndex) {
4008 unsigned int i;
4009 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4010 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4012 * Also get the start index in, but only loop over all elements if there's something to add at all.
4014 #define FIXSRC(type) \
4015 if(strided.u.s.type.VBO) { \
4016 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4017 strided.u.s.type.VBO = 0; \
4018 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4019 ENTER_GL(); \
4020 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4021 vb->vbo = 0; \
4022 LEAVE_GL(); \
4024 if(strided.u.s.type.lpData) { \
4025 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4027 FIXSRC(position);
4028 FIXSRC(blendWeights);
4029 FIXSRC(blendMatrixIndices);
4030 FIXSRC(normal);
4031 FIXSRC(pSize);
4032 FIXSRC(diffuse);
4033 FIXSRC(specular);
4034 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4035 FIXSRC(texCoords[i]);
4037 FIXSRC(position2);
4038 FIXSRC(normal2);
4039 FIXSRC(tangent);
4040 FIXSRC(binormal);
4041 FIXSRC(tessFactor);
4042 FIXSRC(fog);
4043 FIXSRC(depth);
4044 FIXSRC(sample);
4045 #undef FIXSRC
4048 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4051 /*****
4052 * Get / Set Texture Stage States
4053 * TODO: Verify against dx9 definitions
4054 *****/
4055 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4057 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4059 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4061 if (Stage >= MAX_TEXTURES) {
4062 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4063 return WINED3D_OK;
4066 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4067 This->updateStateBlock->textureState[Stage][Type] = Value;
4069 if (This->isRecordingState) {
4070 TRACE("Recording... not performing anything\n");
4071 return WINED3D_OK;
4074 /* Checked after the assignments to allow proper stateblock recording */
4075 if(oldValue == Value) {
4076 TRACE("App is setting the old value over, nothing to do\n");
4077 return WINED3D_OK;
4080 if(Stage > This->stateBlock->lowest_disabled_stage &&
4081 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4082 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4083 * Changes in other states are important on disabled stages too
4085 return WINED3D_OK;
4088 if(Type == WINED3DTSS_COLOROP) {
4089 int i;
4091 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4092 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4093 * they have to be disabled
4095 * The current stage is dirtified below.
4097 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4098 TRACE("Additionally dirtifying stage %d\n", i);
4099 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4101 This->stateBlock->lowest_disabled_stage = Stage;
4102 TRACE("New lowest disabled: %d\n", Stage);
4103 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4104 /* Previously disabled stage enabled. Stages above it may need enabling
4105 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4106 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4108 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4111 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4112 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4113 break;
4115 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4118 This->stateBlock->lowest_disabled_stage = i;
4119 TRACE("New lowest disabled: %d\n", i);
4121 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4122 /* TODO: Built a stage -> texture unit mapping for register combiners */
4126 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4128 return WINED3D_OK;
4131 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4134 *pValue = This->updateStateBlock->textureState[Stage][Type];
4135 return WINED3D_OK;
4138 /*****
4139 * Get / Set Texture
4140 *****/
4141 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4143 IWineD3DBaseTexture *oldTexture;
4145 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4147 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4148 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4151 oldTexture = This->updateStateBlock->textures[Stage];
4153 if(pTexture != NULL) {
4154 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4156 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4157 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4158 return WINED3DERR_INVALIDCALL;
4160 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4163 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4164 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4166 This->updateStateBlock->changed.textures[Stage] = TRUE;
4167 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4168 This->updateStateBlock->textures[Stage] = pTexture;
4170 /* Handle recording of state blocks */
4171 if (This->isRecordingState) {
4172 TRACE("Recording... not performing anything\n");
4173 return WINED3D_OK;
4176 if(oldTexture == pTexture) {
4177 TRACE("App is setting the same texture again, nothing to do\n");
4178 return WINED3D_OK;
4181 /** NOTE: MSDN says that setTexture increases the reference count,
4182 * and the the application must set the texture back to null (or have a leaky application),
4183 * This means we should pass the refcount up to the parent
4184 *******************************/
4185 if (NULL != This->updateStateBlock->textures[Stage]) {
4186 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4187 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4189 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4190 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4191 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4192 * so the COLOROP and ALPHAOP have to be dirtified.
4194 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4197 if(bindCount == 1) {
4198 new->baseTexture.sampler = Stage;
4200 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4204 if (NULL != oldTexture) {
4205 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4206 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4208 IWineD3DBaseTexture_Release(oldTexture);
4209 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4214 if(bindCount && old->baseTexture.sampler == Stage) {
4215 int i;
4216 /* Have to do a search for the other sampler(s) where the texture is bound to
4217 * Shouldn't happen as long as apps bind a texture only to one stage
4219 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4220 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4221 if(This->updateStateBlock->textures[i] == oldTexture) {
4222 old->baseTexture.sampler = i;
4223 break;
4229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4231 return WINED3D_OK;
4234 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4237 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4239 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4240 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4243 *ppTexture=This->stateBlock->textures[Stage];
4244 if (*ppTexture)
4245 IWineD3DBaseTexture_AddRef(*ppTexture);
4247 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4249 return WINED3D_OK;
4252 /*****
4253 * Get Back Buffer
4254 *****/
4255 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4256 IWineD3DSurface **ppBackBuffer) {
4257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4258 IWineD3DSwapChain *swapChain;
4259 HRESULT hr;
4261 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4263 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4264 if (hr == WINED3D_OK) {
4265 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4266 IWineD3DSwapChain_Release(swapChain);
4267 } else {
4268 *ppBackBuffer = NULL;
4270 return hr;
4273 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4275 WARN("(%p) : stub, calling idirect3d for now\n", This);
4276 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4279 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4281 IWineD3DSwapChain *swapChain;
4282 HRESULT hr;
4284 if(iSwapChain > 0) {
4285 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4286 if (hr == WINED3D_OK) {
4287 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4288 IWineD3DSwapChain_Release(swapChain);
4289 } else {
4290 FIXME("(%p) Error getting display mode\n", This);
4292 } else {
4293 /* Don't read the real display mode,
4294 but return the stored mode instead. X11 can't change the color
4295 depth, and some apps are pretty angry if they SetDisplayMode from
4296 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4298 Also don't relay to the swapchain because with ddraw it's possible
4299 that there isn't a swapchain at all */
4300 pMode->Width = This->ddraw_width;
4301 pMode->Height = This->ddraw_height;
4302 pMode->Format = This->ddraw_format;
4303 pMode->RefreshRate = 0;
4304 hr = WINED3D_OK;
4307 return hr;
4310 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4312 TRACE("(%p)->(%p)\n", This, hWnd);
4314 if(This->ddraw_fullscreen) {
4315 if(This->ddraw_window && This->ddraw_window != hWnd) {
4316 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4318 if(hWnd && This->ddraw_window != hWnd) {
4319 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4323 This->ddraw_window = hWnd;
4324 return WINED3D_OK;
4327 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4329 TRACE("(%p)->(%p)\n", This, hWnd);
4331 *hWnd = This->ddraw_window;
4332 return WINED3D_OK;
4335 /*****
4336 * Stateblock related functions
4337 *****/
4339 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4341 IWineD3DStateBlockImpl *object;
4342 HRESULT temp_result;
4343 int i;
4345 ERR("(%p)\n", This);
4347 if (This->isRecordingState) {
4348 return WINED3DERR_INVALIDCALL;
4351 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4352 if (NULL == object ) {
4353 FIXME("(%p)Error allocating memory for stateblock\n", This);
4354 return E_OUTOFMEMORY;
4356 TRACE("(%p) created object %p\n", This, object);
4357 object->wineD3DDevice= This;
4358 /** FIXME: object->parent = parent; **/
4359 object->parent = NULL;
4360 object->blockType = WINED3DSBT_RECORDED;
4361 object->ref = 1;
4362 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4364 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4365 list_init(&object->lightMap[i]);
4368 temp_result = allocate_shader_constants(object);
4369 if (WINED3D_OK != temp_result)
4370 return temp_result;
4372 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4373 This->updateStateBlock = object;
4374 This->isRecordingState = TRUE;
4376 TRACE("(%p) recording stateblock %p\n",This , object);
4377 return WINED3D_OK;
4380 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4382 unsigned int i, j;
4383 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4385 if (!This->isRecordingState) {
4386 FIXME("(%p) not recording! returning error\n", This);
4387 *ppStateBlock = NULL;
4388 return WINED3DERR_INVALIDCALL;
4391 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4392 if(object->changed.renderState[i]) {
4393 object->contained_render_states[object->num_contained_render_states] = i;
4394 object->num_contained_render_states++;
4397 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4398 if(object->changed.transform[i]) {
4399 object->contained_transform_states[object->num_contained_transform_states] = i;
4400 object->num_contained_transform_states++;
4403 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4404 if(object->changed.vertexShaderConstantsF[i]) {
4405 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4406 object->num_contained_vs_consts_f++;
4409 for(i = 0; i < MAX_CONST_I; i++) {
4410 if(object->changed.vertexShaderConstantsI[i]) {
4411 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4412 object->num_contained_vs_consts_i++;
4415 for(i = 0; i < MAX_CONST_B; i++) {
4416 if(object->changed.vertexShaderConstantsB[i]) {
4417 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4418 object->num_contained_vs_consts_b++;
4421 for(i = 0; i < MAX_CONST_I; i++) {
4422 if(object->changed.pixelShaderConstantsI[i]) {
4423 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4424 object->num_contained_ps_consts_i++;
4427 for(i = 0; i < MAX_CONST_B; i++) {
4428 if(object->changed.pixelShaderConstantsB[i]) {
4429 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4430 object->num_contained_ps_consts_b++;
4433 for(i = 0; i < MAX_TEXTURES; i++) {
4434 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4435 if(object->changed.textureState[i][j]) {
4436 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4437 object->contained_tss_states[object->num_contained_tss_states].state = j;
4438 object->num_contained_tss_states++;
4442 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4443 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4444 if(object->changed.samplerState[i][j]) {
4445 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4446 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4447 object->num_contained_sampler_states++;
4452 *ppStateBlock = (IWineD3DStateBlock*) object;
4453 This->isRecordingState = FALSE;
4454 This->updateStateBlock = This->stateBlock;
4455 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4456 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4457 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4458 return WINED3D_OK;
4461 /*****
4462 * Scene related functions
4463 *****/
4464 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4465 /* At the moment we have no need for any functionality at the beginning
4466 of a scene */
4467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4468 TRACE("(%p)\n", This);
4470 if(This->inScene) {
4471 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4472 return WINED3DERR_INVALIDCALL;
4474 This->inScene = TRUE;
4475 return WINED3D_OK;
4478 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 TRACE("(%p)\n", This);
4482 if(!This->inScene) {
4483 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4484 return WINED3DERR_INVALIDCALL;
4487 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4488 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4490 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4491 ENTER_GL();
4492 glFlush();
4493 checkGLcall("glFlush");
4494 LEAVE_GL();
4496 This->inScene = FALSE;
4497 return WINED3D_OK;
4500 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4501 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4502 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4504 IWineD3DSwapChain *swapChain = NULL;
4505 int i;
4506 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4508 TRACE("(%p) Presenting the frame\n", This);
4510 for(i = 0 ; i < swapchains ; i ++) {
4512 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4513 TRACE("presentinng chain %d, %p\n", i, swapChain);
4514 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4515 IWineD3DSwapChain_Release(swapChain);
4518 return WINED3D_OK;
4521 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4522 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4524 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4526 GLbitfield glMask = 0;
4527 unsigned int i;
4528 CONST WINED3DRECT* curRect;
4530 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4531 Count, pRects, Flags, Color, Z, Stencil);
4533 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4534 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4535 /* TODO: What about depth stencil buffers without stencil bits? */
4536 return WINED3DERR_INVALIDCALL;
4539 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4540 * and not the last active one.
4542 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4543 ENTER_GL();
4545 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4546 apply_fbo_state(iface);
4549 if (Count > 0 && pRects) {
4550 curRect = pRects;
4551 } else {
4552 curRect = NULL;
4555 /* Only set the values up once, as they are not changing */
4556 if (Flags & WINED3DCLEAR_STENCIL) {
4557 glClearStencil(Stencil);
4558 checkGLcall("glClearStencil");
4559 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4560 glStencilMask(0xFFFFFFFF);
4563 if (Flags & WINED3DCLEAR_ZBUFFER) {
4564 glDepthMask(GL_TRUE);
4565 glClearDepth(Z);
4566 checkGLcall("glClearDepth");
4567 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4571 if (Flags & WINED3DCLEAR_TARGET) {
4572 TRACE("Clearing screen with glClear to color %x\n", Color);
4573 glClearColor(D3DCOLOR_R(Color),
4574 D3DCOLOR_G(Color),
4575 D3DCOLOR_B(Color),
4576 D3DCOLOR_A(Color));
4577 checkGLcall("glClearColor");
4579 /* Clear ALL colors! */
4580 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4581 glMask = glMask | GL_COLOR_BUFFER_BIT;
4584 if (!curRect) {
4585 /* In drawable flag is set below */
4587 if (This->render_offscreen) {
4588 glScissor(This->stateBlock->viewport.X,
4589 This->stateBlock->viewport.Y,
4590 This->stateBlock->viewport.Width,
4591 This->stateBlock->viewport.Height);
4592 } else {
4593 glScissor(This->stateBlock->viewport.X,
4594 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4595 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4596 This->stateBlock->viewport.Width,
4597 This->stateBlock->viewport.Height);
4599 checkGLcall("glScissor");
4600 glClear(glMask);
4601 checkGLcall("glClear");
4602 } else {
4603 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4604 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4606 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4607 curRect[0].x2 < target->currentDesc.Width ||
4608 curRect[0].y2 < target->currentDesc.Height) {
4609 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4610 blt_to_drawable(This, target);
4614 /* Now process each rect in turn */
4615 for (i = 0; i < Count; i++) {
4616 /* Note gl uses lower left, width/height */
4617 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4618 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4619 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4620 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4622 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4623 * The rectangle is not cleared, no error is returned, but further rectanlges are
4624 * still cleared if they are valid
4626 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4627 TRACE("Rectangle with negative dimensions, ignoring\n");
4628 continue;
4631 if(This->render_offscreen) {
4632 glScissor(curRect[i].x1, curRect[i].y1,
4633 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4634 } else {
4635 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4636 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4638 checkGLcall("glScissor");
4640 glClear(glMask);
4641 checkGLcall("glClear");
4645 /* Restore the old values (why..?) */
4646 if (Flags & WINED3DCLEAR_STENCIL) {
4647 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4649 if (Flags & WINED3DCLEAR_TARGET) {
4650 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4651 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4652 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4653 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4654 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4657 LEAVE_GL();
4659 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4660 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4662 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4663 target->Flags |= SFLAG_INTEXTURE;
4664 target->Flags &= ~SFLAG_INSYSMEM;
4665 } else {
4666 target->Flags |= SFLAG_INDRAWABLE;
4667 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4669 return WINED3D_OK;
4672 /*****
4673 * Drawing functions
4674 *****/
4675 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4676 UINT PrimitiveCount) {
4678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4680 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4681 debug_d3dprimitivetype(PrimitiveType),
4682 StartVertex, PrimitiveCount);
4684 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4685 if(This->stateBlock->streamIsUP) {
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4687 This->stateBlock->streamIsUP = FALSE;
4690 if(This->stateBlock->loadBaseVertexIndex != 0) {
4691 This->stateBlock->loadBaseVertexIndex = 0;
4692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4694 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4695 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4696 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4697 return WINED3D_OK;
4700 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4701 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4702 WINED3DPRIMITIVETYPE PrimitiveType,
4703 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4706 UINT idxStride = 2;
4707 IWineD3DIndexBuffer *pIB;
4708 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4709 GLuint vbo;
4711 pIB = This->stateBlock->pIndexData;
4712 if (!pIB) {
4713 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4714 * without an index buffer set. (The first time at least...)
4715 * D3D8 simply dies, but I doubt it can do much harm to return
4716 * D3DERR_INVALIDCALL there as well. */
4717 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4718 return WINED3DERR_INVALIDCALL;
4721 if(This->stateBlock->streamIsUP) {
4722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4723 This->stateBlock->streamIsUP = FALSE;
4725 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4727 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4728 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4729 minIndex, NumVertices, startIndex, primCount);
4731 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4732 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4733 idxStride = 2;
4734 } else {
4735 idxStride = 4;
4738 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4739 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4743 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4744 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4746 return WINED3D_OK;
4749 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4750 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4751 UINT VertexStreamZeroStride) {
4752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4755 debug_d3dprimitivetype(PrimitiveType),
4756 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4758 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4759 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4760 This->stateBlock->streamOffset[0] = 0;
4761 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4762 This->stateBlock->streamIsUP = TRUE;
4763 This->stateBlock->loadBaseVertexIndex = 0;
4765 /* TODO: Only mark dirty if drawing from a different UP address */
4766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4768 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4769 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4771 /* MSDN specifies stream zero settings must be set to NULL */
4772 This->stateBlock->streamStride[0] = 0;
4773 This->stateBlock->streamSource[0] = NULL;
4775 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4776 * the new stream sources or use UP drawing again
4778 return WINED3D_OK;
4781 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4782 UINT MinVertexIndex, UINT NumVertices,
4783 UINT PrimitiveCount, CONST void* pIndexData,
4784 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4785 UINT VertexStreamZeroStride) {
4786 int idxStride;
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4789 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4790 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4791 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4792 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4794 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4795 idxStride = 2;
4796 } else {
4797 idxStride = 4;
4800 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4801 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4802 This->stateBlock->streamIsUP = TRUE;
4803 This->stateBlock->streamOffset[0] = 0;
4804 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4806 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4807 This->stateBlock->baseVertexIndex = 0;
4808 This->stateBlock->loadBaseVertexIndex = 0;
4809 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4811 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4813 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4815 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4816 This->stateBlock->streamSource[0] = NULL;
4817 This->stateBlock->streamStride[0] = 0;
4818 This->stateBlock->pIndexData = NULL;
4819 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4820 * SetStreamSource to specify a vertex buffer
4823 return WINED3D_OK;
4826 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4829 /* Mark the state dirty until we have nicer tracking
4830 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4831 * that value.
4833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4834 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4835 This->stateBlock->baseVertexIndex = 0;
4836 This->up_strided = DrawPrimStrideData;
4837 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4838 This->up_strided = NULL;
4839 return WINED3D_OK;
4842 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4844 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4846 /* Mark the state dirty until we have nicer tracking
4847 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4848 * that value.
4850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4852 This->stateBlock->streamIsUP = TRUE;
4853 This->stateBlock->baseVertexIndex = 0;
4854 This->up_strided = DrawPrimStrideData;
4855 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4856 This->up_strided = NULL;
4857 return WINED3D_OK;
4861 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4862 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 HRESULT hr = WINED3D_OK;
4865 WINED3DRESOURCETYPE sourceType;
4866 WINED3DRESOURCETYPE destinationType;
4867 int i ,levels;
4869 /* TODO: think about moving the code into IWineD3DBaseTexture */
4871 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4873 /* verify that the source and destination textures aren't NULL */
4874 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4875 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4876 This, pSourceTexture, pDestinationTexture);
4877 hr = WINED3DERR_INVALIDCALL;
4880 if (pSourceTexture == pDestinationTexture) {
4881 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4882 This, pSourceTexture, pDestinationTexture);
4883 hr = WINED3DERR_INVALIDCALL;
4885 /* Verify that the source and destination textures are the same type */
4886 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4887 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4889 if (sourceType != destinationType) {
4890 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4891 This);
4892 hr = WINED3DERR_INVALIDCALL;
4895 /* check that both textures have the identical numbers of levels */
4896 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4897 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4898 hr = WINED3DERR_INVALIDCALL;
4901 if (WINED3D_OK == hr) {
4903 /* Make sure that the destination texture is loaded */
4904 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4906 /* Update every surface level of the texture */
4907 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4909 switch (sourceType) {
4910 case WINED3DRTYPE_TEXTURE:
4912 IWineD3DSurface *srcSurface;
4913 IWineD3DSurface *destSurface;
4915 for (i = 0 ; i < levels ; ++i) {
4916 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4917 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4918 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4919 IWineD3DSurface_Release(srcSurface);
4920 IWineD3DSurface_Release(destSurface);
4921 if (WINED3D_OK != hr) {
4922 WARN("(%p) : Call to update surface failed\n", This);
4923 return hr;
4927 break;
4928 case WINED3DRTYPE_CUBETEXTURE:
4930 IWineD3DSurface *srcSurface;
4931 IWineD3DSurface *destSurface;
4932 WINED3DCUBEMAP_FACES faceType;
4934 for (i = 0 ; i < levels ; ++i) {
4935 /* Update each cube face */
4936 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4937 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4938 if (WINED3D_OK != hr) {
4939 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4940 } else {
4941 TRACE("Got srcSurface %p\n", srcSurface);
4943 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4944 if (WINED3D_OK != hr) {
4945 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4946 } else {
4947 TRACE("Got desrSurface %p\n", destSurface);
4949 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4950 IWineD3DSurface_Release(srcSurface);
4951 IWineD3DSurface_Release(destSurface);
4952 if (WINED3D_OK != hr) {
4953 WARN("(%p) : Call to update surface failed\n", This);
4954 return hr;
4959 break;
4960 #if 0 /* TODO: Add support for volume textures */
4961 case WINED3DRTYPE_VOLUMETEXTURE:
4963 IWineD3DVolume srcVolume = NULL;
4964 IWineD3DSurface destVolume = NULL;
4966 for (i = 0 ; i < levels ; ++i) {
4967 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4968 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4969 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4970 IWineD3DVolume_Release(srcSurface);
4971 IWineD3DVolume_Release(destSurface);
4972 if (WINED3D_OK != hr) {
4973 WARN("(%p) : Call to update volume failed\n", This);
4974 return hr;
4978 break;
4979 #endif
4980 default:
4981 FIXME("(%p) : Unsupported source and destination type\n", This);
4982 hr = WINED3DERR_INVALIDCALL;
4986 return hr;
4989 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
4990 IWineD3DSwapChain *swapChain;
4991 HRESULT hr;
4992 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4993 if(hr == WINED3D_OK) {
4994 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
4995 IWineD3DSwapChain_Release(swapChain);
4997 return hr;
5000 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5002 /* return a sensible default */
5003 *pNumPasses = 1;
5004 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5005 FIXME("(%p) : stub\n", This);
5006 return WINED3D_OK;
5009 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5010 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5011 int j;
5012 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5013 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5014 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5015 return WINED3DERR_INVALIDCALL;
5017 for (j = 0; j < 256; ++j) {
5018 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5019 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5020 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5021 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5023 TRACE("(%p) : returning\n", This);
5024 return WINED3D_OK;
5027 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5029 int j;
5030 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5031 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5032 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5033 return WINED3DERR_INVALIDCALL;
5035 for (j = 0; j < 256; ++j) {
5036 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5037 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5038 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5039 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5041 TRACE("(%p) : returning\n", This);
5042 return WINED3D_OK;
5045 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5047 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5048 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5049 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5050 return WINED3DERR_INVALIDCALL;
5052 /*TODO: stateblocks */
5053 This->currentPalette = PaletteNumber;
5054 TRACE("(%p) : returning\n", This);
5055 return WINED3D_OK;
5058 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5060 if (PaletteNumber == NULL) {
5061 WARN("(%p) : returning Invalid Call\n", This);
5062 return WINED3DERR_INVALIDCALL;
5064 /*TODO: stateblocks */
5065 *PaletteNumber = This->currentPalette;
5066 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5067 return WINED3D_OK;
5070 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5072 static BOOL showFixmes = TRUE;
5073 if (showFixmes) {
5074 FIXME("(%p) : stub\n", This);
5075 showFixmes = FALSE;
5078 This->softwareVertexProcessing = bSoftware;
5079 return WINED3D_OK;
5083 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5085 static BOOL showFixmes = TRUE;
5086 if (showFixmes) {
5087 FIXME("(%p) : stub\n", This);
5088 showFixmes = FALSE;
5090 return This->softwareVertexProcessing;
5094 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5096 IWineD3DSwapChain *swapChain;
5097 HRESULT hr;
5099 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5101 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5102 if(hr == WINED3D_OK){
5103 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5104 IWineD3DSwapChain_Release(swapChain);
5105 }else{
5106 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5108 return hr;
5112 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5114 static BOOL showfixmes = TRUE;
5115 if(nSegments != 0.0f) {
5116 if( showfixmes) {
5117 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5118 showfixmes = FALSE;
5121 return WINED3D_OK;
5124 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5126 static BOOL showfixmes = TRUE;
5127 if( showfixmes) {
5128 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5129 showfixmes = FALSE;
5131 return 0.0f;
5134 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5136 /** TODO: remove casts to IWineD3DSurfaceImpl
5137 * NOTE: move code to surface to accomplish this
5138 ****************************************/
5139 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5140 int srcWidth, srcHeight;
5141 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5142 WINED3DFORMAT destFormat, srcFormat;
5143 UINT destSize;
5144 int srcLeft, destLeft, destTop;
5145 WINED3DPOOL srcPool, destPool;
5146 int offset = 0;
5147 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5148 glDescriptor *glDescription = NULL;
5150 WINED3DSURFACE_DESC winedesc;
5152 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5153 memset(&winedesc, 0, sizeof(winedesc));
5154 winedesc.Width = &srcSurfaceWidth;
5155 winedesc.Height = &srcSurfaceHeight;
5156 winedesc.Pool = &srcPool;
5157 winedesc.Format = &srcFormat;
5159 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5161 winedesc.Width = &destSurfaceWidth;
5162 winedesc.Height = &destSurfaceHeight;
5163 winedesc.Pool = &destPool;
5164 winedesc.Format = &destFormat;
5165 winedesc.Size = &destSize;
5167 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5169 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5170 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5171 return WINED3DERR_INVALIDCALL;
5174 if (destFormat == WINED3DFMT_UNKNOWN) {
5175 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5176 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5178 /* Get the update surface description */
5179 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5182 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5184 ENTER_GL();
5186 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5187 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5188 checkGLcall("glActiveTextureARB");
5191 /* Make sure the surface is loaded and up to date */
5192 IWineD3DSurface_PreLoad(pDestinationSurface);
5194 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5196 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5197 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5198 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5199 srcLeft = pSourceRect ? pSourceRect->left : 0;
5200 destLeft = pDestPoint ? pDestPoint->x : 0;
5201 destTop = pDestPoint ? pDestPoint->y : 0;
5204 /* This function doesn't support compressed textures
5205 the pitch is just bytesPerPixel * width */
5206 if(srcWidth != srcSurfaceWidth || srcLeft ){
5207 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5208 offset += srcLeft * pSrcSurface->bytesPerPixel;
5209 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5211 /* TODO DXT formats */
5213 if(pSourceRect != NULL && pSourceRect->top != 0){
5214 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5216 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5217 ,This
5218 ,glDescription->level
5219 ,destLeft
5220 ,destTop
5221 ,srcWidth
5222 ,srcHeight
5223 ,glDescription->glFormat
5224 ,glDescription->glType
5225 ,IWineD3DSurface_GetData(pSourceSurface)
5228 /* Sanity check */
5229 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5231 /* need to lock the surface to get the data */
5232 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5235 /* TODO: Cube and volume support */
5236 if(rowoffset != 0){
5237 /* not a whole row so we have to do it a line at a time */
5238 int j;
5240 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5241 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5243 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5245 glTexSubImage2D(glDescription->target
5246 ,glDescription->level
5247 ,destLeft
5249 ,srcWidth
5251 ,glDescription->glFormat
5252 ,glDescription->glType
5253 ,data /* could be quicker using */
5255 data += rowoffset;
5258 } else { /* Full width, so just write out the whole texture */
5260 if (WINED3DFMT_DXT1 == destFormat ||
5261 WINED3DFMT_DXT2 == destFormat ||
5262 WINED3DFMT_DXT3 == destFormat ||
5263 WINED3DFMT_DXT4 == destFormat ||
5264 WINED3DFMT_DXT5 == destFormat) {
5265 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5266 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5267 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5268 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5269 } if (destFormat != srcFormat) {
5270 FIXME("Updating mixed format compressed texture is not curretly support\n");
5271 } else {
5272 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5273 glDescription->level,
5274 glDescription->glFormatInternal,
5275 srcWidth,
5276 srcHeight,
5278 destSize,
5279 IWineD3DSurface_GetData(pSourceSurface));
5281 } else {
5282 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5286 } else {
5287 glTexSubImage2D(glDescription->target
5288 ,glDescription->level
5289 ,destLeft
5290 ,destTop
5291 ,srcWidth
5292 ,srcHeight
5293 ,glDescription->glFormat
5294 ,glDescription->glType
5295 ,IWineD3DSurface_GetData(pSourceSurface)
5299 checkGLcall("glTexSubImage2D");
5301 LEAVE_GL();
5303 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5304 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5307 return WINED3D_OK;
5310 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5312 struct WineD3DRectPatch *patch;
5313 unsigned int i;
5314 struct list *e;
5315 BOOL found;
5316 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5318 if(!(Handle || pRectPatchInfo)) {
5319 /* TODO: Write a test for the return value, thus the FIXME */
5320 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5321 return WINED3DERR_INVALIDCALL;
5324 if(Handle) {
5325 i = PATCHMAP_HASHFUNC(Handle);
5326 found = FALSE;
5327 LIST_FOR_EACH(e, &This->patches[i]) {
5328 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5329 if(patch->Handle == Handle) {
5330 found = TRUE;
5331 break;
5335 if(!found) {
5336 TRACE("Patch does not exist. Creating a new one\n");
5337 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5338 patch->Handle = Handle;
5339 list_add_head(&This->patches[i], &patch->entry);
5340 } else {
5341 TRACE("Found existing patch %p\n", patch);
5343 } else {
5344 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5345 * attributes we have to tesselate, read back, and draw. This needs a patch
5346 * management structure instance. Create one.
5348 * A possible improvement is to check if a vertex shader is used, and if not directly
5349 * draw the patch.
5351 FIXME("Drawing an uncached patch. This is slow\n");
5352 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5355 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5356 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5357 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5358 HRESULT hr;
5359 TRACE("Tesselation density or patch info changed, retesselating\n");
5361 if(pRectPatchInfo) {
5362 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5364 patch->numSegs[0] = pNumSegs[0];
5365 patch->numSegs[1] = pNumSegs[1];
5366 patch->numSegs[2] = pNumSegs[2];
5367 patch->numSegs[3] = pNumSegs[3];
5369 hr = tesselate_rectpatch(This, patch);
5370 if(FAILED(hr)) {
5371 WARN("Patch tesselation failed\n");
5373 /* Do not release the handle to store the params of the patch */
5374 if(!Handle) {
5375 HeapFree(GetProcessHeap(), 0, patch);
5377 return hr;
5381 This->currentPatch = patch;
5382 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5383 This->currentPatch = NULL;
5385 /* Destroy uncached patches */
5386 if(!Handle) {
5387 HeapFree(GetProcessHeap(), 0, patch->mem);
5388 HeapFree(GetProcessHeap(), 0, patch);
5390 return WINED3D_OK;
5393 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5394 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5396 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5397 FIXME("(%p) : Stub\n", This);
5398 return WINED3D_OK;
5401 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5403 int i;
5404 struct WineD3DRectPatch *patch;
5405 struct list *e;
5406 TRACE("(%p) Handle(%d)\n", This, Handle);
5408 i = PATCHMAP_HASHFUNC(Handle);
5409 LIST_FOR_EACH(e, &This->patches[i]) {
5410 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5411 if(patch->Handle == Handle) {
5412 TRACE("Deleting patch %p\n", patch);
5413 list_remove(&patch->entry);
5414 HeapFree(GetProcessHeap(), 0, patch->mem);
5415 HeapFree(GetProcessHeap(), 0, patch);
5416 return WINED3D_OK;
5420 /* TODO: Write a test for the return value */
5421 FIXME("Attempt to destroy nonexistant patch\n");
5422 return WINED3DERR_INVALIDCALL;
5425 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5426 HRESULT hr;
5427 IWineD3DSwapChain *swapchain;
5429 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5430 if (SUCCEEDED(hr)) {
5431 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5432 return swapchain;
5435 return NULL;
5438 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 if (!*fbo) {
5442 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5443 checkGLcall("glGenFramebuffersEXT()");
5445 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5446 checkGLcall("glBindFramebuffer()");
5449 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5450 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5451 IWineD3DBaseTextureImpl *texture_impl;
5452 GLenum texttarget, target;
5453 GLint old_binding;
5455 texttarget = surface_impl->glDescription.target;
5456 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5457 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5459 IWineD3DSurface_PreLoad(surface);
5461 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5462 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5463 glBindTexture(target, old_binding);
5465 /* Update base texture states array */
5466 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5467 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5468 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5469 if (texture_impl->baseTexture.bindCount) {
5470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5473 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5476 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget, surface_impl->glDescription.textureName, 0));
5478 checkGLcall("attach_surface_fbo");
5481 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5483 IWineD3DSwapChain *swapchain;
5485 swapchain = get_swapchain(surface);
5486 if (swapchain) {
5487 GLenum buffer;
5489 TRACE("Surface %p is onscreen\n", surface);
5491 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5492 buffer = surface_get_gl_buffer(surface, swapchain);
5493 glDrawBuffer(buffer);
5494 checkGLcall("glDrawBuffer()");
5495 } else {
5496 TRACE("Surface %p is offscreen\n", surface);
5497 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5498 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5501 if (rect) {
5502 glEnable(GL_SCISSOR_TEST);
5503 if(!swapchain) {
5504 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5505 } else {
5506 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5507 rect->x2 - rect->x1, rect->y2 - rect->y1);
5509 checkGLcall("glScissor");
5510 } else {
5511 glDisable(GL_SCISSOR_TEST);
5513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5515 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5516 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5518 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5519 glClear(GL_COLOR_BUFFER_BIT);
5520 checkGLcall("glClear");
5522 if (This->render_offscreen) {
5523 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5524 } else {
5525 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5526 checkGLcall("glBindFramebuffer()");
5529 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5530 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5531 glDrawBuffer(GL_BACK);
5532 checkGLcall("glDrawBuffer()");
5536 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5538 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5539 WINEDDBLTFX BltFx;
5540 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5542 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5543 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5544 return WINED3DERR_INVALIDCALL;
5547 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5548 color_fill_fbo(iface, pSurface, pRect, color);
5549 return WINED3D_OK;
5550 } else {
5551 /* Just forward this to the DirectDraw blitting engine */
5552 memset(&BltFx, 0, sizeof(BltFx));
5553 BltFx.dwSize = sizeof(BltFx);
5554 BltFx.u5.dwFillColor = color;
5555 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5559 /* rendertarget and deptth stencil functions */
5560 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5563 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5564 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5565 return WINED3DERR_INVALIDCALL;
5568 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5569 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5570 /* Note inc ref on returned surface */
5571 if(*ppRenderTarget != NULL)
5572 IWineD3DSurface_AddRef(*ppRenderTarget);
5573 return WINED3D_OK;
5576 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5578 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5579 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5580 IWineD3DSwapChainImpl *Swapchain;
5581 HRESULT hr;
5583 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5585 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5586 if(hr != WINED3D_OK) {
5587 ERR("Can't get the swapchain\n");
5588 return hr;
5591 /* Make sure to release the swapchain */
5592 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5594 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5595 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5596 return WINED3DERR_INVALIDCALL;
5598 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5599 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5600 return WINED3DERR_INVALIDCALL;
5603 if(Swapchain->frontBuffer != Front) {
5604 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5606 if(Swapchain->frontBuffer)
5607 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5608 Swapchain->frontBuffer = Front;
5610 if(Swapchain->frontBuffer) {
5611 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5615 if(Back && !Swapchain->backBuffer) {
5616 /* We need memory for the back buffer array - only one back buffer this way */
5617 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5618 if(!Swapchain->backBuffer) {
5619 ERR("Out of memory\n");
5620 return E_OUTOFMEMORY;
5624 if(Swapchain->backBuffer[0] != Back) {
5625 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5627 /* What to do about the context here in the case of multithreading? Not sure.
5628 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5630 ENTER_GL();
5631 if(!Swapchain->backBuffer[0]) {
5632 /* GL was told to draw to the front buffer at creation,
5633 * undo that
5635 glDrawBuffer(GL_BACK);
5636 checkGLcall("glDrawBuffer(GL_BACK)");
5637 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5638 Swapchain->presentParms.BackBufferCount = 1;
5639 } else if (!Back) {
5640 /* That makes problems - disable for now */
5641 /* glDrawBuffer(GL_FRONT); */
5642 checkGLcall("glDrawBuffer(GL_FRONT)");
5643 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5644 Swapchain->presentParms.BackBufferCount = 0;
5646 LEAVE_GL();
5648 if(Swapchain->backBuffer[0])
5649 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5650 Swapchain->backBuffer[0] = Back;
5652 if(Swapchain->backBuffer[0]) {
5653 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5654 } else {
5655 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5660 return WINED3D_OK;
5663 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5665 *ppZStencilSurface = This->depthStencilBuffer;
5666 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5668 if(*ppZStencilSurface != NULL) {
5669 /* Note inc ref on returned surface */
5670 IWineD3DSurface_AddRef(*ppZStencilSurface);
5672 return WINED3D_OK;
5675 /* TODO: Handle stencil attachments */
5676 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5680 TRACE("Set depth stencil to %p\n", depth_stencil);
5682 if (depth_stencil_impl) {
5683 if (depth_stencil_impl->current_renderbuffer) {
5684 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5685 checkGLcall("glFramebufferRenderbufferEXT()");
5686 } else {
5687 IWineD3DBaseTextureImpl *texture_impl;
5688 GLenum texttarget, target;
5689 GLint old_binding = 0;
5691 texttarget = depth_stencil_impl->glDescription.target;
5692 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5693 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5695 IWineD3DSurface_PreLoad(depth_stencil);
5697 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5698 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5699 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5700 glBindTexture(target, old_binding);
5702 /* Update base texture states array */
5703 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5704 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5705 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5706 if (texture_impl->baseTexture.bindCount) {
5707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5710 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5713 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget, depth_stencil_impl->glDescription.textureName, 0));
5714 checkGLcall("glFramebufferTexture2DEXT()");
5716 } else {
5717 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5718 checkGLcall("glFramebufferTexture2DEXT()");
5722 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5724 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5726 TRACE("Set render target %u to %p\n", idx, render_target);
5728 if (rtimpl) {
5729 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5730 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5731 } else {
5732 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5733 checkGLcall("glFramebufferTexture2DEXT()");
5735 This->draw_buffers[idx] = GL_NONE;
5739 static void check_fbo_status(IWineD3DDevice *iface) {
5740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5741 GLenum status;
5743 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5744 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5745 TRACE("FBO complete\n");
5746 } else {
5747 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5749 /* Dump the FBO attachments */
5750 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5751 IWineD3DSurfaceImpl *attachment;
5752 int i;
5754 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5755 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5756 if (attachment) {
5757 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5758 attachment->pow2Width, attachment->pow2Height);
5761 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5762 if (attachment) {
5763 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5764 attachment->pow2Width, attachment->pow2Height);
5770 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5772 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5773 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5775 if (!ds_impl) return FALSE;
5777 if (ds_impl->current_renderbuffer) {
5778 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5779 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5782 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5783 rt_impl->pow2Height != ds_impl->pow2Height);
5786 void apply_fbo_state(IWineD3DDevice *iface) {
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5788 unsigned int i;
5790 if (This->render_offscreen) {
5791 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5793 /* Apply render targets */
5794 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5795 IWineD3DSurface *render_target = This->render_targets[i];
5796 if (This->fbo_color_attachments[i] != render_target) {
5797 set_render_target_fbo(iface, i, render_target);
5798 This->fbo_color_attachments[i] = render_target;
5802 /* Apply depth targets */
5803 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5804 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5805 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5807 if (This->stencilBufferTarget) {
5808 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5810 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5811 This->fbo_depth_attachment = This->stencilBufferTarget;
5814 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5815 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5816 checkGLcall("glDrawBuffers()");
5817 } else {
5818 glDrawBuffer(This->draw_buffers[0]);
5819 checkGLcall("glDrawBuffer()");
5821 } else {
5822 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5825 check_fbo_status(iface);
5828 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5829 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5831 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5832 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5833 GLenum gl_filter;
5835 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5836 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5837 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5838 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5840 switch (filter) {
5841 case WINED3DTEXF_LINEAR:
5842 gl_filter = GL_LINEAR;
5843 break;
5845 default:
5846 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5847 case WINED3DTEXF_NONE:
5848 case WINED3DTEXF_POINT:
5849 gl_filter = GL_NEAREST;
5850 break;
5853 /* Attach src surface to src fbo */
5854 src_swapchain = get_swapchain(src_surface);
5855 if (src_swapchain) {
5856 GLenum buffer;
5858 TRACE("Source surface %p is onscreen\n", src_surface);
5859 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5861 ENTER_GL();
5862 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5863 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5864 glReadBuffer(buffer);
5865 checkGLcall("glReadBuffer()");
5867 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5868 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5869 } else {
5870 TRACE("Source surface %p is offscreen\n", src_surface);
5871 ENTER_GL();
5872 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5873 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5874 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5875 checkGLcall("glReadBuffer()");
5877 LEAVE_GL();
5879 /* Attach dst surface to dst fbo */
5880 dst_swapchain = get_swapchain(dst_surface);
5881 if (dst_swapchain) {
5882 GLenum buffer;
5884 TRACE("Destination surface %p is onscreen\n", dst_surface);
5885 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5887 ENTER_GL();
5888 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5889 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5890 glDrawBuffer(buffer);
5891 checkGLcall("glDrawBuffer()");
5893 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5894 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5895 } else {
5896 TRACE("Destination surface %p is offscreen\n", dst_surface);
5898 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5899 if(!src_swapchain) {
5900 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5903 ENTER_GL();
5904 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5905 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5906 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5907 checkGLcall("glDrawBuffer()");
5909 glDisable(GL_SCISSOR_TEST);
5910 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5912 if (flip) {
5913 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5914 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5915 checkGLcall("glBlitFramebuffer()");
5916 } else {
5917 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5918 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5919 checkGLcall("glBlitFramebuffer()");
5922 if (This->render_offscreen) {
5923 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5924 } else {
5925 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5926 checkGLcall("glBindFramebuffer()");
5929 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5930 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5931 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5932 glDrawBuffer(GL_BACK);
5933 checkGLcall("glDrawBuffer()");
5935 LEAVE_GL();
5938 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5940 WINED3DVIEWPORT viewport;
5942 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5944 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5945 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5946 return WINED3DERR_INVALIDCALL;
5949 /* MSDN says that null disables the render target
5950 but a device must always be associated with a render target
5951 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5953 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5954 for more details
5956 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5957 FIXME("Trying to set render target 0 to NULL\n");
5958 return WINED3DERR_INVALIDCALL;
5960 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5961 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);
5962 return WINED3DERR_INVALIDCALL;
5965 /* If we are trying to set what we already have, don't bother */
5966 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
5967 TRACE("Trying to do a NOP SetRenderTarget operation\n");
5968 return WINED3D_OK;
5970 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
5971 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
5972 This->render_targets[RenderTargetIndex] = pRenderTarget;
5974 /* Render target 0 is special */
5975 if(RenderTargetIndex == 0) {
5976 /* Finally, reset the viewport as the MSDN states. */
5977 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
5978 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
5979 viewport.X = 0;
5980 viewport.Y = 0;
5981 viewport.MaxZ = 1.0f;
5982 viewport.MinZ = 0.0f;
5983 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
5984 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
5985 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
5987 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
5989 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
5990 * ctx properly.
5991 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
5992 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
5994 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
5996 return WINED3D_OK;
5999 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6001 HRESULT hr = WINED3D_OK;
6002 IWineD3DSurface *tmp;
6004 TRACE("(%p) Swapping z-buffer\n",This);
6006 if (pNewZStencil == This->stencilBufferTarget) {
6007 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6008 } else {
6009 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6010 * depending on the renter target implementation being used.
6011 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6012 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6013 * stencil buffer and incure an extra memory overhead
6014 ******************************************************/
6016 tmp = This->stencilBufferTarget;
6017 This->stencilBufferTarget = pNewZStencil;
6018 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6019 /* should we be calling the parent or the wined3d surface? */
6020 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6021 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6022 hr = WINED3D_OK;
6024 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6025 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6026 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6032 return hr;
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6036 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6038 /* TODO: the use of Impl is deprecated. */
6039 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6040 WINED3DLOCKED_RECT lockedRect;
6042 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6044 /* some basic validation checks */
6045 if(This->cursorTexture) {
6046 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6047 ENTER_GL();
6048 glDeleteTextures(1, &This->cursorTexture);
6049 LEAVE_GL();
6050 This->cursorTexture = 0;
6053 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6054 This->haveHardwareCursor = TRUE;
6055 else
6056 This->haveHardwareCursor = FALSE;
6058 if(pCursorBitmap) {
6059 WINED3DLOCKED_RECT rect;
6061 /* MSDN: Cursor must be A8R8G8B8 */
6062 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6063 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6064 return WINED3DERR_INVALIDCALL;
6067 /* MSDN: Cursor must be smaller than the display mode */
6068 if(pSur->currentDesc.Width > This->ddraw_width ||
6069 pSur->currentDesc.Height > This->ddraw_height) {
6070 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);
6071 return WINED3DERR_INVALIDCALL;
6074 if (!This->haveHardwareCursor) {
6075 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6077 /* Do not store the surface's pointer because the application may
6078 * release it after setting the cursor image. Windows doesn't
6079 * addref the set surface, so we can't do this either without
6080 * creating circular refcount dependencies. Copy out the gl texture
6081 * instead.
6083 This->cursorWidth = pSur->currentDesc.Width;
6084 This->cursorHeight = pSur->currentDesc.Height;
6085 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6087 const GlPixelFormatDesc *glDesc;
6088 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6089 char *mem, *bits = (char *)rect.pBits;
6090 GLint intfmt = glDesc->glInternal;
6091 GLint format = glDesc->glFormat;
6092 GLint type = glDesc->glType;
6093 INT height = This->cursorHeight;
6094 INT width = This->cursorWidth;
6095 INT bpp = tableEntry->bpp;
6096 INT i;
6098 /* Reformat the texture memory (pitch and width can be
6099 * different) */
6100 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6101 for(i = 0; i < height; i++)
6102 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6103 IWineD3DSurface_UnlockRect(pCursorBitmap);
6104 ENTER_GL();
6106 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6107 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6108 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6111 /* Make sure that a proper texture unit is selected */
6112 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6113 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6114 checkGLcall("glActiveTextureARB");
6116 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6117 /* Create a new cursor texture */
6118 glGenTextures(1, &This->cursorTexture);
6119 checkGLcall("glGenTextures");
6120 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6121 checkGLcall("glBindTexture");
6122 /* Copy the bitmap memory into the cursor texture */
6123 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6124 HeapFree(GetProcessHeap(), 0, mem);
6125 checkGLcall("glTexImage2D");
6127 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6128 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6129 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6132 LEAVE_GL();
6134 else
6136 FIXME("A cursor texture was not returned.\n");
6137 This->cursorTexture = 0;
6140 else
6142 /* Draw a hardware cursor */
6143 ICONINFO cursorInfo;
6144 HCURSOR cursor;
6145 /* Create and clear maskBits because it is not needed for
6146 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6147 * chunks. */
6148 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6149 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6150 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6151 WINED3DLOCK_NO_DIRTY_UPDATE |
6152 WINED3DLOCK_READONLY
6154 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6155 pSur->currentDesc.Height);
6157 cursorInfo.fIcon = FALSE;
6158 cursorInfo.xHotspot = XHotSpot;
6159 cursorInfo.yHotspot = YHotSpot;
6160 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6161 pSur->currentDesc.Height, 1,
6162 1, &maskBits);
6163 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6164 pSur->currentDesc.Height, 1,
6165 32, lockedRect.pBits);
6166 IWineD3DSurface_UnlockRect(pCursorBitmap);
6167 /* Create our cursor and clean up. */
6168 cursor = CreateIconIndirect(&cursorInfo);
6169 SetCursor(cursor);
6170 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6171 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6172 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6173 This->hardwareCursor = cursor;
6174 HeapFree(GetProcessHeap(), 0, maskBits);
6178 This->xHotSpot = XHotSpot;
6179 This->yHotSpot = YHotSpot;
6180 return WINED3D_OK;
6183 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6184 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6185 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6187 This->xScreenSpace = XScreenSpace;
6188 This->yScreenSpace = YScreenSpace;
6190 return;
6194 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6196 BOOL oldVisible = This->bCursorVisible;
6197 POINT pt;
6199 TRACE("(%p) : visible(%d)\n", This, bShow);
6202 * When ShowCursor is first called it should make the cursor appear at the OS's last
6203 * known cursor position. Because of this, some applications just repetitively call
6204 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6206 GetCursorPos(&pt);
6207 This->xScreenSpace = pt.x;
6208 This->yScreenSpace = pt.y;
6210 if (This->haveHardwareCursor) {
6211 This->bCursorVisible = bShow;
6212 if (bShow)
6213 SetCursor(This->hardwareCursor);
6214 else
6215 SetCursor(NULL);
6217 else
6219 if (This->cursorTexture)
6220 This->bCursorVisible = bShow;
6223 return oldVisible;
6226 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6228 TRACE("(%p) : state (%u)\n", This, This->state);
6229 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6230 switch (This->state) {
6231 case WINED3D_OK:
6232 return WINED3D_OK;
6233 case WINED3DERR_DEVICELOST:
6235 ResourceList *resourceList = This->resources;
6236 while (NULL != resourceList) {
6237 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6238 return WINED3DERR_DEVICENOTRESET;
6239 resourceList = resourceList->next;
6241 return WINED3DERR_DEVICELOST;
6243 case WINED3DERR_DRIVERINTERNALERROR:
6244 return WINED3DERR_DRIVERINTERNALERROR;
6247 /* Unknown state */
6248 return WINED3DERR_DRIVERINTERNALERROR;
6252 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6254 /** FIXME: Resource tracking needs to be done,
6255 * The closes we can do to this is set the priorities of all managed textures low
6256 * and then reset them.
6257 ***********************************************************/
6258 FIXME("(%p) : stub\n", This);
6259 return WINED3D_OK;
6262 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6263 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6265 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6266 if(surface->Flags & SFLAG_DIBSECTION) {
6267 /* Release the DC */
6268 SelectObject(surface->hDC, surface->dib.holdbitmap);
6269 DeleteDC(surface->hDC);
6270 /* Release the DIB section */
6271 DeleteObject(surface->dib.DIBsection);
6272 surface->dib.bitmap_data = NULL;
6273 surface->resource.allocatedMemory = NULL;
6274 surface->Flags &= ~SFLAG_DIBSECTION;
6276 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6277 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6278 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6279 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6280 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6281 } else {
6282 surface->pow2Width = surface->pow2Height = 1;
6283 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6284 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6286 if(surface->glDescription.textureName) {
6287 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6288 ENTER_GL();
6289 glDeleteTextures(1, &surface->glDescription.textureName);
6290 LEAVE_GL();
6291 surface->glDescription.textureName = 0;
6292 surface->Flags &= ~SFLAG_CLIENT;
6294 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6295 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6296 surface->Flags |= SFLAG_NONPOW2;
6297 } else {
6298 surface->Flags &= ~SFLAG_NONPOW2;
6300 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6301 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6304 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6306 IWineD3DSwapChainImpl *swapchain;
6307 HRESULT hr;
6308 BOOL DisplayModeChanged = FALSE;
6309 WINED3DDISPLAYMODE mode;
6310 TRACE("(%p)\n", This);
6312 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6313 if(FAILED(hr)) {
6314 ERR("Failed to get the first implicit swapchain\n");
6315 return hr;
6318 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6319 * on an existing gl context, so there's no real need for recreation.
6321 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6323 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6325 TRACE("New params:\n");
6326 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6327 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6328 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6329 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6330 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6331 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6332 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6333 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6334 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6335 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6336 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6337 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6338 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6340 /* No special treatment of these parameters. Just store them */
6341 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6342 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6343 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6344 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6346 /* What to do about these? */
6347 if(pPresentationParameters->BackBufferCount != 0 &&
6348 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6349 ERR("Cannot change the back buffer count yet\n");
6351 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6352 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6353 ERR("Cannot change the back buffer format yet\n");
6355 if(pPresentationParameters->hDeviceWindow != NULL &&
6356 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6357 ERR("Cannot change the device window yet\n");
6359 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6360 ERR("What do do about a changed auto depth stencil parameter?\n");
6363 if(pPresentationParameters->Windowed) {
6364 mode.Width = swapchain->orig_width;
6365 mode.Height = swapchain->orig_height;
6366 mode.RefreshRate = 0;
6367 mode.Format = swapchain->presentParms.BackBufferFormat;
6368 } else {
6369 mode.Width = pPresentationParameters->BackBufferWidth;
6370 mode.Height = pPresentationParameters->BackBufferHeight;
6371 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6372 mode.Format = swapchain->presentParms.BackBufferFormat;
6374 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6375 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6376 pPresentationParameters->BackBufferWidth,
6377 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6380 /* Should Width == 800 && Height == 0 set 800x600? */
6381 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6382 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6383 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6385 WINED3DVIEWPORT vp;
6386 int i;
6388 vp.X = 0;
6389 vp.Y = 0;
6390 vp.Width = pPresentationParameters->BackBufferWidth;
6391 vp.Height = pPresentationParameters->BackBufferHeight;
6392 vp.MinZ = 0;
6393 vp.MaxZ = 1;
6395 if(!pPresentationParameters->Windowed) {
6396 DisplayModeChanged = TRUE;
6398 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6399 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6401 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6402 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6403 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6406 /* Now set the new viewport */
6407 IWineD3DDevice_SetViewport(iface, &vp);
6410 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6411 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6412 DisplayModeChanged) {
6414 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6415 if(!pPresentationParameters->Windowed) {
6416 IWineD3DDevice_SetFullscreen(iface, TRUE);
6419 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6421 /* Switching out of fullscreen mode? First set the original res, then change the window */
6422 if(pPresentationParameters->Windowed) {
6423 IWineD3DDevice_SetFullscreen(iface, FALSE);
6425 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6428 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6429 return WINED3D_OK;
6432 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6434 /** FIXME: always true at the moment **/
6435 if(!bEnableDialogs) {
6436 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6438 return WINED3D_OK;
6442 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6444 TRACE("(%p) : pParameters %p\n", This, pParameters);
6446 *pParameters = This->createParms;
6447 return WINED3D_OK;
6450 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6451 IWineD3DSwapChain *swapchain;
6452 HRESULT hrc = WINED3D_OK;
6454 TRACE("Relaying to swapchain\n");
6456 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6457 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6458 IWineD3DSwapChain_Release(swapchain);
6460 return;
6463 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6464 IWineD3DSwapChain *swapchain;
6465 HRESULT hrc = WINED3D_OK;
6467 TRACE("Relaying to swapchain\n");
6469 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6470 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6471 IWineD3DSwapChain_Release(swapchain);
6473 return;
6477 /** ********************************************************
6478 * Notification functions
6479 ** ********************************************************/
6480 /** This function must be called in the release of a resource when ref == 0,
6481 * the contents of resource must still be correct,
6482 * any handels to other resource held by the caller must be closed
6483 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6484 *****************************************************/
6485 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6487 ResourceList* resourceList;
6489 TRACE("(%p) : resource %p\n", This, resource);
6490 /* add a new texture to the frot of the linked list */
6491 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6492 resourceList->resource = resource;
6494 /* Get the old head */
6495 resourceList->next = This->resources;
6497 This->resources = resourceList;
6498 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6500 return;
6503 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 ResourceList* resourceList = NULL;
6506 ResourceList* previousResourceList = NULL;
6508 TRACE("(%p) : resource %p\n", This, resource);
6510 resourceList = This->resources;
6512 while (resourceList != NULL) {
6513 if(resourceList->resource == resource) break;
6514 previousResourceList = resourceList;
6515 resourceList = resourceList->next;
6518 if (resourceList == NULL) {
6519 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6520 return;
6521 } else {
6522 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6524 /* make sure we don't leave a hole in the list */
6525 if (previousResourceList != NULL) {
6526 previousResourceList->next = resourceList->next;
6527 } else {
6528 This->resources = resourceList->next;
6531 return;
6535 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6537 int counter;
6539 TRACE("(%p) : resource %p\n", This, resource);
6540 switch(IWineD3DResource_GetType(resource)){
6541 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6542 case WINED3DRTYPE_SURFACE: {
6543 unsigned int i;
6545 /* Cleanup any FBO attachments if d3d is enabled */
6546 if(This->d3d_initialized) {
6547 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6548 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6549 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6550 set_render_target_fbo(iface, i, NULL);
6551 This->fbo_color_attachments[i] = NULL;
6554 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6555 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6556 set_depth_stencil_fbo(iface, NULL);
6557 This->fbo_depth_attachment = NULL;
6561 break;
6563 case WINED3DRTYPE_TEXTURE:
6564 case WINED3DRTYPE_CUBETEXTURE:
6565 case WINED3DRTYPE_VOLUMETEXTURE:
6566 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6567 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6568 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6569 This->stateBlock->textures[counter] = NULL;
6571 if (This->updateStateBlock != This->stateBlock ){
6572 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6573 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6574 This->updateStateBlock->textures[counter] = NULL;
6578 break;
6579 case WINED3DRTYPE_VOLUME:
6580 /* TODO: nothing really? */
6581 break;
6582 case WINED3DRTYPE_VERTEXBUFFER:
6583 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6585 int streamNumber;
6586 TRACE("Cleaning up stream pointers\n");
6588 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6589 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6590 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6592 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6593 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6594 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6595 This->updateStateBlock->streamSource[streamNumber] = 0;
6596 /* Set changed flag? */
6599 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) */
6600 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6601 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6602 This->stateBlock->streamSource[streamNumber] = 0;
6605 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6606 else { /* This shouldn't happen */
6607 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6609 #endif
6613 break;
6614 case WINED3DRTYPE_INDEXBUFFER:
6615 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6616 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6617 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6618 This->updateStateBlock->pIndexData = NULL;
6621 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6622 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6623 This->stateBlock->pIndexData = NULL;
6627 break;
6628 default:
6629 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6630 break;
6634 /* Remove the resoruce from the resourceStore */
6635 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6637 TRACE("Resource released\n");
6641 /**********************************************************
6642 * IWineD3DDevice VTbl follows
6643 **********************************************************/
6645 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6647 /*** IUnknown methods ***/
6648 IWineD3DDeviceImpl_QueryInterface,
6649 IWineD3DDeviceImpl_AddRef,
6650 IWineD3DDeviceImpl_Release,
6651 /*** IWineD3DDevice methods ***/
6652 IWineD3DDeviceImpl_GetParent,
6653 /*** Creation methods**/
6654 IWineD3DDeviceImpl_CreateVertexBuffer,
6655 IWineD3DDeviceImpl_CreateIndexBuffer,
6656 IWineD3DDeviceImpl_CreateStateBlock,
6657 IWineD3DDeviceImpl_CreateSurface,
6658 IWineD3DDeviceImpl_CreateTexture,
6659 IWineD3DDeviceImpl_CreateVolumeTexture,
6660 IWineD3DDeviceImpl_CreateVolume,
6661 IWineD3DDeviceImpl_CreateCubeTexture,
6662 IWineD3DDeviceImpl_CreateQuery,
6663 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6664 IWineD3DDeviceImpl_CreateVertexDeclaration,
6665 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6666 IWineD3DDeviceImpl_CreateVertexShader,
6667 IWineD3DDeviceImpl_CreatePixelShader,
6668 IWineD3DDeviceImpl_CreatePalette,
6669 /*** Odd functions **/
6670 IWineD3DDeviceImpl_Init3D,
6671 IWineD3DDeviceImpl_Uninit3D,
6672 IWineD3DDeviceImpl_SetFullscreen,
6673 IWineD3DDeviceImpl_SetMultithreaded,
6674 IWineD3DDeviceImpl_EvictManagedResources,
6675 IWineD3DDeviceImpl_GetAvailableTextureMem,
6676 IWineD3DDeviceImpl_GetBackBuffer,
6677 IWineD3DDeviceImpl_GetCreationParameters,
6678 IWineD3DDeviceImpl_GetDeviceCaps,
6679 IWineD3DDeviceImpl_GetDirect3D,
6680 IWineD3DDeviceImpl_GetDisplayMode,
6681 IWineD3DDeviceImpl_SetDisplayMode,
6682 IWineD3DDeviceImpl_GetHWND,
6683 IWineD3DDeviceImpl_SetHWND,
6684 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6685 IWineD3DDeviceImpl_GetRasterStatus,
6686 IWineD3DDeviceImpl_GetSwapChain,
6687 IWineD3DDeviceImpl_Reset,
6688 IWineD3DDeviceImpl_SetDialogBoxMode,
6689 IWineD3DDeviceImpl_SetCursorProperties,
6690 IWineD3DDeviceImpl_SetCursorPosition,
6691 IWineD3DDeviceImpl_ShowCursor,
6692 IWineD3DDeviceImpl_TestCooperativeLevel,
6693 /*** Getters and setters **/
6694 IWineD3DDeviceImpl_SetClipPlane,
6695 IWineD3DDeviceImpl_GetClipPlane,
6696 IWineD3DDeviceImpl_SetClipStatus,
6697 IWineD3DDeviceImpl_GetClipStatus,
6698 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6699 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6700 IWineD3DDeviceImpl_SetDepthStencilSurface,
6701 IWineD3DDeviceImpl_GetDepthStencilSurface,
6702 IWineD3DDeviceImpl_SetFVF,
6703 IWineD3DDeviceImpl_GetFVF,
6704 IWineD3DDeviceImpl_SetGammaRamp,
6705 IWineD3DDeviceImpl_GetGammaRamp,
6706 IWineD3DDeviceImpl_SetIndices,
6707 IWineD3DDeviceImpl_GetIndices,
6708 IWineD3DDeviceImpl_SetBaseVertexIndex,
6709 IWineD3DDeviceImpl_GetBaseVertexIndex,
6710 IWineD3DDeviceImpl_SetLight,
6711 IWineD3DDeviceImpl_GetLight,
6712 IWineD3DDeviceImpl_SetLightEnable,
6713 IWineD3DDeviceImpl_GetLightEnable,
6714 IWineD3DDeviceImpl_SetMaterial,
6715 IWineD3DDeviceImpl_GetMaterial,
6716 IWineD3DDeviceImpl_SetNPatchMode,
6717 IWineD3DDeviceImpl_GetNPatchMode,
6718 IWineD3DDeviceImpl_SetPaletteEntries,
6719 IWineD3DDeviceImpl_GetPaletteEntries,
6720 IWineD3DDeviceImpl_SetPixelShader,
6721 IWineD3DDeviceImpl_GetPixelShader,
6722 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6723 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6724 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6725 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6726 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6727 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6728 IWineD3DDeviceImpl_SetRenderState,
6729 IWineD3DDeviceImpl_GetRenderState,
6730 IWineD3DDeviceImpl_SetRenderTarget,
6731 IWineD3DDeviceImpl_GetRenderTarget,
6732 IWineD3DDeviceImpl_SetFrontBackBuffers,
6733 IWineD3DDeviceImpl_SetSamplerState,
6734 IWineD3DDeviceImpl_GetSamplerState,
6735 IWineD3DDeviceImpl_SetScissorRect,
6736 IWineD3DDeviceImpl_GetScissorRect,
6737 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6738 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6739 IWineD3DDeviceImpl_SetStreamSource,
6740 IWineD3DDeviceImpl_GetStreamSource,
6741 IWineD3DDeviceImpl_SetStreamSourceFreq,
6742 IWineD3DDeviceImpl_GetStreamSourceFreq,
6743 IWineD3DDeviceImpl_SetTexture,
6744 IWineD3DDeviceImpl_GetTexture,
6745 IWineD3DDeviceImpl_SetTextureStageState,
6746 IWineD3DDeviceImpl_GetTextureStageState,
6747 IWineD3DDeviceImpl_SetTransform,
6748 IWineD3DDeviceImpl_GetTransform,
6749 IWineD3DDeviceImpl_SetVertexDeclaration,
6750 IWineD3DDeviceImpl_GetVertexDeclaration,
6751 IWineD3DDeviceImpl_SetVertexShader,
6752 IWineD3DDeviceImpl_GetVertexShader,
6753 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6754 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6755 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6756 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6757 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6758 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6759 IWineD3DDeviceImpl_SetViewport,
6760 IWineD3DDeviceImpl_GetViewport,
6761 IWineD3DDeviceImpl_MultiplyTransform,
6762 IWineD3DDeviceImpl_ValidateDevice,
6763 IWineD3DDeviceImpl_ProcessVertices,
6764 /*** State block ***/
6765 IWineD3DDeviceImpl_BeginStateBlock,
6766 IWineD3DDeviceImpl_EndStateBlock,
6767 /*** Scene management ***/
6768 IWineD3DDeviceImpl_BeginScene,
6769 IWineD3DDeviceImpl_EndScene,
6770 IWineD3DDeviceImpl_Present,
6771 IWineD3DDeviceImpl_Clear,
6772 /*** Drawing ***/
6773 IWineD3DDeviceImpl_DrawPrimitive,
6774 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6775 IWineD3DDeviceImpl_DrawPrimitiveUP,
6776 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6777 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6778 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6779 IWineD3DDeviceImpl_DrawRectPatch,
6780 IWineD3DDeviceImpl_DrawTriPatch,
6781 IWineD3DDeviceImpl_DeletePatch,
6782 IWineD3DDeviceImpl_ColorFill,
6783 IWineD3DDeviceImpl_UpdateTexture,
6784 IWineD3DDeviceImpl_UpdateSurface,
6785 IWineD3DDeviceImpl_GetFrontBufferData,
6786 /*** object tracking ***/
6787 IWineD3DDeviceImpl_ResourceReleased
6791 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6792 WINED3DRS_ALPHABLENDENABLE ,
6793 WINED3DRS_ALPHAFUNC ,
6794 WINED3DRS_ALPHAREF ,
6795 WINED3DRS_ALPHATESTENABLE ,
6796 WINED3DRS_BLENDOP ,
6797 WINED3DRS_COLORWRITEENABLE ,
6798 WINED3DRS_DESTBLEND ,
6799 WINED3DRS_DITHERENABLE ,
6800 WINED3DRS_FILLMODE ,
6801 WINED3DRS_FOGDENSITY ,
6802 WINED3DRS_FOGEND ,
6803 WINED3DRS_FOGSTART ,
6804 WINED3DRS_LASTPIXEL ,
6805 WINED3DRS_SHADEMODE ,
6806 WINED3DRS_SRCBLEND ,
6807 WINED3DRS_STENCILENABLE ,
6808 WINED3DRS_STENCILFAIL ,
6809 WINED3DRS_STENCILFUNC ,
6810 WINED3DRS_STENCILMASK ,
6811 WINED3DRS_STENCILPASS ,
6812 WINED3DRS_STENCILREF ,
6813 WINED3DRS_STENCILWRITEMASK ,
6814 WINED3DRS_STENCILZFAIL ,
6815 WINED3DRS_TEXTUREFACTOR ,
6816 WINED3DRS_WRAP0 ,
6817 WINED3DRS_WRAP1 ,
6818 WINED3DRS_WRAP2 ,
6819 WINED3DRS_WRAP3 ,
6820 WINED3DRS_WRAP4 ,
6821 WINED3DRS_WRAP5 ,
6822 WINED3DRS_WRAP6 ,
6823 WINED3DRS_WRAP7 ,
6824 WINED3DRS_ZENABLE ,
6825 WINED3DRS_ZFUNC ,
6826 WINED3DRS_ZWRITEENABLE
6829 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6830 WINED3DTSS_ADDRESSW ,
6831 WINED3DTSS_ALPHAARG0 ,
6832 WINED3DTSS_ALPHAARG1 ,
6833 WINED3DTSS_ALPHAARG2 ,
6834 WINED3DTSS_ALPHAOP ,
6835 WINED3DTSS_BUMPENVLOFFSET ,
6836 WINED3DTSS_BUMPENVLSCALE ,
6837 WINED3DTSS_BUMPENVMAT00 ,
6838 WINED3DTSS_BUMPENVMAT01 ,
6839 WINED3DTSS_BUMPENVMAT10 ,
6840 WINED3DTSS_BUMPENVMAT11 ,
6841 WINED3DTSS_COLORARG0 ,
6842 WINED3DTSS_COLORARG1 ,
6843 WINED3DTSS_COLORARG2 ,
6844 WINED3DTSS_COLOROP ,
6845 WINED3DTSS_RESULTARG ,
6846 WINED3DTSS_TEXCOORDINDEX ,
6847 WINED3DTSS_TEXTURETRANSFORMFLAGS
6850 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6851 WINED3DSAMP_ADDRESSU ,
6852 WINED3DSAMP_ADDRESSV ,
6853 WINED3DSAMP_ADDRESSW ,
6854 WINED3DSAMP_BORDERCOLOR ,
6855 WINED3DSAMP_MAGFILTER ,
6856 WINED3DSAMP_MINFILTER ,
6857 WINED3DSAMP_MIPFILTER ,
6858 WINED3DSAMP_MIPMAPLODBIAS ,
6859 WINED3DSAMP_MAXMIPLEVEL ,
6860 WINED3DSAMP_MAXANISOTROPY ,
6861 WINED3DSAMP_SRGBTEXTURE ,
6862 WINED3DSAMP_ELEMENTINDEX
6865 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6866 WINED3DRS_AMBIENT ,
6867 WINED3DRS_AMBIENTMATERIALSOURCE ,
6868 WINED3DRS_CLIPPING ,
6869 WINED3DRS_CLIPPLANEENABLE ,
6870 WINED3DRS_COLORVERTEX ,
6871 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6872 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6873 WINED3DRS_FOGDENSITY ,
6874 WINED3DRS_FOGEND ,
6875 WINED3DRS_FOGSTART ,
6876 WINED3DRS_FOGTABLEMODE ,
6877 WINED3DRS_FOGVERTEXMODE ,
6878 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6879 WINED3DRS_LIGHTING ,
6880 WINED3DRS_LOCALVIEWER ,
6881 WINED3DRS_MULTISAMPLEANTIALIAS ,
6882 WINED3DRS_MULTISAMPLEMASK ,
6883 WINED3DRS_NORMALIZENORMALS ,
6884 WINED3DRS_PATCHEDGESTYLE ,
6885 WINED3DRS_POINTSCALE_A ,
6886 WINED3DRS_POINTSCALE_B ,
6887 WINED3DRS_POINTSCALE_C ,
6888 WINED3DRS_POINTSCALEENABLE ,
6889 WINED3DRS_POINTSIZE ,
6890 WINED3DRS_POINTSIZE_MAX ,
6891 WINED3DRS_POINTSIZE_MIN ,
6892 WINED3DRS_POINTSPRITEENABLE ,
6893 WINED3DRS_RANGEFOGENABLE ,
6894 WINED3DRS_SPECULARMATERIALSOURCE ,
6895 WINED3DRS_TWEENFACTOR ,
6896 WINED3DRS_VERTEXBLEND
6899 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6900 WINED3DTSS_TEXCOORDINDEX ,
6901 WINED3DTSS_TEXTURETRANSFORMFLAGS
6904 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6905 WINED3DSAMP_DMAPOFFSET
6908 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6909 DWORD rep = StateTable[state].representative;
6910 DWORD idx;
6911 BYTE shift;
6912 UINT i;
6913 WineD3DContext *context;
6915 if(!rep) return;
6916 for(i = 0; i < This->numContexts; i++) {
6917 context = This->contexts[i];
6918 if(isStateDirty(context, rep)) continue;
6920 context->dirtyArray[context->numDirtyEntries++] = rep;
6921 idx = rep >> 5;
6922 shift = rep & 0x1f;
6923 context->isStateDirty[idx] |= (1 << shift);