wined3d: Override backbufferformat in window mode.
[wine.git] / dlls / wined3d / device.c
blob425ffe2270dd72831991effaa1623f76878b8f64
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 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 } else if (Type == WINED3DSBT_PIXELSTATE) {
519 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
520 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
522 object->changed.pixelShader = TRUE;
524 /* Pixel Shader Constants */
525 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
526 object->contained_ps_consts_f[i] = i;
527 object->changed.pixelShaderConstantsF[i] = TRUE;
529 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
530 for (i = 0; i < MAX_CONST_B; ++i) {
531 object->contained_ps_consts_b[i] = i;
532 object->changed.pixelShaderConstantsB[i] = TRUE;
534 object->num_contained_ps_consts_b = MAX_CONST_B;
535 for (i = 0; i < MAX_CONST_I; ++i) {
536 object->contained_ps_consts_i[i] = i;
537 object->changed.pixelShaderConstantsI[i] = TRUE;
539 object->num_contained_ps_consts_i = MAX_CONST_I;
541 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
542 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
543 object->contained_render_states[i] = SavedPixelStates_R[i];
545 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
546 for (j = 0; j < MAX_TEXTURES; j++) {
547 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
548 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
549 object->contained_tss_states[object->num_contained_tss_states].stage = j;
550 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
551 object->num_contained_tss_states++;
554 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
555 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
556 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
557 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
558 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
559 object->num_contained_sampler_states++;
563 } else if (Type == WINED3DSBT_VERTEXSTATE) {
565 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
566 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
568 object->changed.vertexShader = TRUE;
570 /* Vertex Shader Constants */
571 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
572 object->changed.vertexShaderConstantsF[i] = TRUE;
573 object->contained_vs_consts_f[i] = i;
575 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
576 for (i = 0; i < MAX_CONST_B; ++i) {
577 object->changed.vertexShaderConstantsB[i] = TRUE;
578 object->contained_vs_consts_b[i] = i;
580 object->num_contained_vs_consts_b = MAX_CONST_B;
581 for (i = 0; i < MAX_CONST_I; ++i) {
582 object->changed.vertexShaderConstantsI[i] = TRUE;
583 object->contained_vs_consts_i[i] = i;
585 object->num_contained_vs_consts_i = MAX_CONST_I;
586 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
587 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
588 object->contained_render_states[i] = SavedVertexStates_R[i];
590 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
591 for (j = 0; j < MAX_TEXTURES; j++) {
592 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
593 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
594 object->contained_tss_states[object->num_contained_tss_states].stage = j;
595 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
596 object->num_contained_tss_states++;
599 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
600 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
601 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
602 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
603 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
604 object->num_contained_sampler_states++;
608 for(j = 0; j < LIGHTMAP_SIZE; j++) {
609 struct list *e;
610 LIST_FOR_EACH(e, &object->lightMap[j]) {
611 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
612 light->changed = TRUE;
613 light->enabledChanged = TRUE;
616 } else {
617 FIXME("Unrecognized state block type %d\n", Type);
620 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
621 return WINED3D_OK;
624 /* ************************************
625 MSDN:
626 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
628 Discard
629 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
633 ******************************** */
635 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) {
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
638 unsigned int Size = 1;
639 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
640 TRACE("(%p) Create surface\n",This);
642 /** FIXME: Check ranges on the inputs are valid
643 * MSDN
644 * MultisampleQuality
645 * [in] Quality level. The valid range is between zero and one less than the level
646 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
647 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
648 * values of paired render targets, depth stencil surfaces, and the MultiSample type
649 * must all match.
650 *******************************/
654 * TODO: Discard MSDN
655 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
657 * If this flag is set, the contents of the depth stencil buffer will be
658 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
659 * with a different depth surface.
661 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
662 ***************************/
664 if(MultisampleQuality < 0) {
665 FIXME("Invalid multisample level %d\n", MultisampleQuality);
666 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
669 if(MultisampleQuality > 0) {
670 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
671 MultisampleQuality=0;
674 /** FIXME: Check that the format is supported
675 * by the device.
676 *******************************/
678 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
679 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
680 * space!
681 *********************************/
682 if (WINED3DFMT_UNKNOWN == Format) {
683 Size = 0;
684 } else if (Format == WINED3DFMT_DXT1) {
685 /* DXT1 is half byte per pixel */
686 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
688 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
689 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
690 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
691 } else {
692 /* The pitch is a multiple of 4 bytes */
693 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
694 Size *= Height;
697 /** Create and initialise the surface resource **/
698 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
699 /* "Standalone" surface */
700 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
702 object->currentDesc.Width = Width;
703 object->currentDesc.Height = Height;
704 object->currentDesc.MultiSampleType = MultiSample;
705 object->currentDesc.MultiSampleQuality = MultisampleQuality;
706 object->glDescription.level = Level;
708 /* Flags */
709 object->Flags = 0;
710 object->Flags |= Discard ? SFLAG_DISCARD : 0;
711 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
712 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
715 if (WINED3DFMT_UNKNOWN != Format) {
716 object->bytesPerPixel = tableEntry->bpp;
717 } else {
718 object->bytesPerPixel = 0;
721 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
723 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
725 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
726 * this function is too deep to need to care about things like this.
727 * Levels need to be checked too, and possibly Type since they all affect what can be done.
728 * ****************************************/
729 switch(Pool) {
730 case WINED3DPOOL_SCRATCH:
731 if(!Lockable)
732 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
733 "which are mutually exclusive, setting lockable to TRUE\n");
734 Lockable = TRUE;
735 break;
736 case WINED3DPOOL_SYSTEMMEM:
737 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
738 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
739 case WINED3DPOOL_MANAGED:
740 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
741 "Usage of DYNAMIC which are mutually exclusive, not doing "
742 "anything just telling you.\n");
743 break;
744 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
745 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
746 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
747 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
748 break;
749 default:
750 FIXME("(%p) Unknown pool %d\n", This, Pool);
751 break;
754 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
755 FIXME("Trying to create a render target that isn't in the default pool\n");
758 /* mark the texture as dirty so that it gets loaded first time around*/
759 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
760 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
761 This, Width, Height, Format, debug_d3dformat(Format),
762 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
764 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
765 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
766 This->ddraw_primary = (IWineD3DSurface *) object;
768 /* Look at the implementation and set the correct Vtable */
769 switch(Impl) {
770 case SURFACE_OPENGL:
771 /* Check if a 3D adapter is available when creating gl surfaces */
772 if(!This->adapter) {
773 ERR("OpenGL surfaces are not available without opengl\n");
774 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
775 HeapFree(GetProcessHeap(), 0, object);
776 return WINED3DERR_NOTAVAILABLE;
778 break;
780 case SURFACE_GDI:
781 object->lpVtbl = &IWineGDISurface_Vtbl;
782 break;
784 default:
785 /* To be sure to catch this */
786 ERR("Unknown requested surface implementation %d!\n", Impl);
787 IWineD3DSurface_Release((IWineD3DSurface *) object);
788 return WINED3DERR_INVALIDCALL;
791 list_init(&object->renderbuffers);
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
805 unsigned int i;
806 UINT tmpW;
807 UINT tmpH;
808 HRESULT hr;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
831 pow2Width = Width;
832 pow2Height = Height;
833 } else {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
847 if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
885 return WINED3D_OK;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
898 unsigned int i;
899 UINT tmpW;
900 UINT tmpH;
901 UINT tmpD;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
921 if (Levels == 0) {
922 object->baseTexture.levels++;
923 tmpW = Width;
924 tmpH = Height;
925 tmpD = Depth;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
936 tmpW = Width;
937 tmpH = Height;
938 tmpD = Depth;
940 for (i = 0; i < object->baseTexture.levels; i++)
942 HRESULT hr;
943 /* Create the volume */
944 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
945 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
947 if(FAILED(hr)) {
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
950 *ppVolumeTexture = NULL;
951 return hr;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
957 /* calcualte the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
960 tmpD = max(1, tmpD >> 1);
963 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
964 TRACE("(%p) : Created volume texture %p\n", This, object);
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
969 UINT Width, UINT Height, UINT Depth,
970 DWORD Usage,
971 WINED3DFORMAT Format, WINED3DPOOL Pool,
972 IWineD3DVolume** ppVolume,
973 HANDLE* pSharedHandle, IUnknown *parent) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
977 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
979 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
982 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
984 object->currentDesc.Width = Width;
985 object->currentDesc.Height = Height;
986 object->currentDesc.Depth = Depth;
987 object->bytesPerPixel = formatDesc->bpp;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object->lockable = TRUE;
991 object->locked = FALSE;
992 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
993 object->dirty = TRUE;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
998 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
999 UINT Levels, DWORD Usage,
1000 WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DCubeTexture **ppCubeTexture,
1002 HANDLE *pSharedHandle, IUnknown *parent,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1007 unsigned int i, j;
1008 UINT tmpW;
1009 HRESULT hr;
1010 unsigned int pow2EdgeLength = EdgeLength;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN >= Format) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1016 return WINED3DERR_INVALIDCALL;
1019 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1020 WARN("(%p) : Tried to create not supported cube texture\n", This);
1021 return WINED3DERR_INVALIDCALL;
1024 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1025 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1027 TRACE("(%p) Create Cube Texture\n", This);
1029 /** Non-power2 support **/
1031 /* Find the nearest pow2 match */
1032 pow2EdgeLength = 1;
1033 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1035 object->edgeLength = EdgeLength;
1036 /* TODO: support for native non-power 2 */
1037 /* Precalculated scaling for 'faked' non power of two texture coords */
1038 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1040 /* Calculate levels for mip mapping */
1041 if (Levels == 0) {
1042 object->baseTexture.levels++;
1043 tmpW = EdgeLength;
1044 while (tmpW > 1) {
1045 tmpW = max(1, tmpW >> 1);
1046 object->baseTexture.levels++;
1048 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1051 /* Generate all the surfaces */
1052 tmpW = EdgeLength;
1053 for (i = 0; i < object->baseTexture.levels; i++) {
1055 /* Create the 6 faces */
1056 for (j = 0; j < 6; j++) {
1058 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1059 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1061 if(hr!= WINED3D_OK) {
1062 /* clean up */
1063 int k;
1064 int l;
1065 for (l = 0; l < j; l++) {
1066 IWineD3DSurface_Release(object->surfaces[j][i]);
1068 for (k = 0; k < i; k++) {
1069 for (l = 0; l < 6; l++) {
1070 IWineD3DSurface_Release(object->surfaces[l][j]);
1074 FIXME("(%p) Failed to create surface\n",object);
1075 HeapFree(GetProcessHeap(),0,object);
1076 *ppCubeTexture = NULL;
1077 return hr;
1079 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1080 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1082 tmpW = max(1, tmpW >> 1);
1085 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1086 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1087 return WINED3D_OK;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1093 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1095 /* Just a check to see if we support this type of query */
1096 switch(Type) {
1097 case WINED3DQUERYTYPE_OCCLUSION:
1098 TRACE("(%p) occlusion query\n", This);
1099 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1100 hr = WINED3D_OK;
1101 else
1102 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1103 break;
1105 case WINED3DQUERYTYPE_EVENT:
1106 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1107 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1108 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1110 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1112 hr = WINED3D_OK;
1113 break;
1115 case WINED3DQUERYTYPE_VCACHE:
1116 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1117 case WINED3DQUERYTYPE_VERTEXSTATS:
1118 case WINED3DQUERYTYPE_TIMESTAMP:
1119 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1120 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1121 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1122 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1123 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1124 case WINED3DQUERYTYPE_PIXELTIMINGS:
1125 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1126 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1127 default:
1128 FIXME("(%p) Unhandled query type %d\n", This, Type);
1130 if(NULL == ppQuery || hr != WINED3D_OK) {
1131 return hr;
1134 D3DCREATEOBJECTINSTANCE(object, Query)
1135 object->type = Type;
1136 /* allocated the 'extended' data based on the type of query requested */
1137 switch(Type){
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1140 TRACE("(%p) Allocating data for an occlusion query\n", This);
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1142 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1143 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1144 break;
1146 case WINED3DQUERYTYPE_EVENT:
1147 if(GL_SUPPORT(APPLE_FENCE)) {
1148 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1149 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1150 checkGLcall("glGenFencesAPPLE");
1151 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1152 } else if(GL_SUPPORT(NV_FENCE)) {
1153 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1154 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1155 checkGLcall("glGenFencesNV");
1156 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1158 break;
1160 case WINED3DQUERYTYPE_VCACHE:
1161 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1162 case WINED3DQUERYTYPE_VERTEXSTATS:
1163 case WINED3DQUERYTYPE_TIMESTAMP:
1164 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1165 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1166 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1167 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1168 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1169 case WINED3DQUERYTYPE_PIXELTIMINGS:
1170 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1171 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1172 default:
1173 object->extendedData = 0;
1174 FIXME("(%p) Unhandled query type %d\n",This , Type);
1176 TRACE("(%p) : Created Query %p\n", This, object);
1177 return WINED3D_OK;
1180 /*****************************************************************************
1181 * IWineD3DDeviceImpl_SetupFullscreenWindow
1183 * Helper function that modifies a HWND's Style and ExStyle for proper
1184 * fullscreen use.
1186 * Params:
1187 * iface: Pointer to the IWineD3DDevice interface
1188 * window: Window to setup
1190 *****************************************************************************/
1191 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1194 LONG style, exStyle;
1195 /* Don't do anything if an original style is stored.
1196 * That shouldn't happen
1198 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1199 if (This->style || This->exStyle) {
1200 ERR("(%p): Want to change the window parameters of HWND %p, but "
1201 "another style is stored for restoration afterwards\n", This, window);
1204 /* Get the parameters and save them */
1205 style = GetWindowLongW(window, GWL_STYLE);
1206 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1207 This->style = style;
1208 This->exStyle = exStyle;
1210 /* Filter out window decorations */
1211 style &= ~WS_CAPTION;
1212 style &= ~WS_THICKFRAME;
1213 exStyle &= ~WS_EX_WINDOWEDGE;
1214 exStyle &= ~WS_EX_CLIENTEDGE;
1216 /* Make sure the window is managed, otherwise we won't get keyboard input */
1217 style |= WS_POPUP | WS_SYSMENU;
1219 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1220 This->style, This->exStyle, style, exStyle);
1222 SetWindowLongW(window, GWL_STYLE, style);
1223 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1225 /* Inform the window about the update. */
1226 SetWindowPos(window, HWND_TOP, 0, 0,
1227 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1228 ShowWindow(window, SW_NORMAL);
1231 /*****************************************************************************
1232 * IWineD3DDeviceImpl_RestoreWindow
1234 * Helper function that restores a windows' properties when taking it out
1235 * of fullscreen mode
1237 * Params:
1238 * iface: Pointer to the IWineD3DDevice interface
1239 * window: Window to setup
1241 *****************************************************************************/
1242 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1246 * switch, do nothing
1248 if (!This->style && !This->exStyle) return;
1250 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1251 This, window, This->style, This->exStyle);
1253 SetWindowLongW(window, GWL_STYLE, This->style);
1254 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1256 /* Delete the old values */
1257 This->style = 0;
1258 This->exStyle = 0;
1260 /* Inform the window about the update */
1261 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1262 0, 0, 0, 0, /* Pos, Size, ignored */
1263 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1266 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1268 IUnknown* parent,
1269 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1270 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 HDC hDc;
1274 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 HRESULT hr = WINED3D_OK;
1276 IUnknown *bufferParent;
1278 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1280 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1281 * does a device hold a reference to a swap chain giving them a lifetime of the device
1282 * or does the swap chain notify the device of its destruction.
1283 *******************************/
1285 /* Check the params */
1286 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1287 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1288 return WINED3DERR_INVALIDCALL;
1289 } else if (pPresentationParameters->BackBufferCount > 1) {
1290 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");
1293 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1295 /*********************
1296 * Lookup the window Handle and the relating X window handle
1297 ********************/
1299 /* Setup hwnd we are using, plus which display this equates to */
1300 object->win_handle = pPresentationParameters->hDeviceWindow;
1301 if (!object->win_handle) {
1302 object->win_handle = This->createParms.hFocusWindow;
1305 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1306 hDc = GetDC(object->win_handle);
1307 TRACE("Using hDc %p\n", hDc);
1309 if (NULL == hDc) {
1310 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1311 return WINED3DERR_NOTAVAILABLE;
1314 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1315 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1316 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1317 ReleaseDC(object->win_handle, hDc);
1319 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1320 * then the corresponding dimension of the client area of the hDeviceWindow
1321 * (or the focus window, if hDeviceWindow is NULL) is taken.
1322 **********************/
1324 if (pPresentationParameters->Windowed &&
1325 ((pPresentationParameters->BackBufferWidth == 0) ||
1326 (pPresentationParameters->BackBufferHeight == 0))) {
1328 RECT Rect;
1329 GetClientRect(object->win_handle, &Rect);
1331 if (pPresentationParameters->BackBufferWidth == 0) {
1332 pPresentationParameters->BackBufferWidth = Rect.right;
1333 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1335 if (pPresentationParameters->BackBufferHeight == 0) {
1336 pPresentationParameters->BackBufferHeight = Rect.bottom;
1337 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1339 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1340 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1341 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1345 /* Put the correct figures in the presentation parameters */
1346 TRACE("Copying across presentation parameters\n");
1347 object->presentParms = *pPresentationParameters;
1349 TRACE("calling rendertarget CB\n");
1350 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1351 parent,
1352 object->presentParms.BackBufferWidth,
1353 object->presentParms.BackBufferHeight,
1354 object->presentParms.BackBufferFormat,
1355 object->presentParms.MultiSampleType,
1356 object->presentParms.MultiSampleQuality,
1357 TRUE /* Lockable */,
1358 &object->frontBuffer,
1359 NULL /* pShared (always null)*/);
1360 if (object->frontBuffer != NULL) {
1361 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1362 } else {
1363 ERR("Failed to create the front buffer\n");
1364 goto error;
1368 * Create an opengl context for the display visual
1369 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1370 * use different properties after that point in time. FIXME: How to handle when requested format
1371 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1372 * it chooses is identical to the one already being used!
1373 **********************************/
1374 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1376 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1377 if(!object->context)
1378 return E_OUTOFMEMORY;
1379 object->num_contexts = 1;
1381 ENTER_GL();
1382 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1383 LEAVE_GL();
1385 if (!object->context[0]) {
1386 ERR("Failed to create a new context\n");
1387 hr = WINED3DERR_NOTAVAILABLE;
1388 goto error;
1389 } else {
1390 TRACE("Context created (HWND=%p, glContext=%p)\n",
1391 object->win_handle, object->context[0]->glCtx);
1394 /*********************
1395 * Windowed / Fullscreen
1396 *******************/
1399 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1400 * so we should really check to see if there is a fullscreen swapchain already
1401 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1402 **************************************/
1404 if (!pPresentationParameters->Windowed) {
1406 DEVMODEW devmode;
1407 HDC hdc;
1408 int bpp = 0;
1409 RECT clip_rc;
1411 /* Get info on the current display setup */
1412 hdc = GetDC(0);
1413 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1414 ReleaseDC(0, hdc);
1416 /* Change the display settings */
1417 memset(&devmode, 0, sizeof(devmode));
1418 devmode.dmSize = sizeof(devmode);
1419 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1420 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1421 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1422 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1423 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1425 /* For GetDisplayMode */
1426 This->ddraw_width = devmode.dmPelsWidth;
1427 This->ddraw_height = devmode.dmPelsHeight;
1428 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1430 IWineD3DDevice_SetFullscreen(iface, TRUE);
1432 /* And finally clip mouse to our screen */
1433 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1434 ClipCursor(&clip_rc);
1437 /*********************
1438 * Create the back, front and stencil buffers
1439 *******************/
1440 if(object->presentParms.BackBufferCount > 0) {
1441 int i;
1443 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1444 if(!object->backBuffer) {
1445 ERR("Out of memory\n");
1446 hr = E_OUTOFMEMORY;
1447 goto error;
1450 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1451 TRACE("calling rendertarget CB\n");
1452 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1453 parent,
1454 object->presentParms.BackBufferWidth,
1455 object->presentParms.BackBufferHeight,
1456 object->presentParms.BackBufferFormat,
1457 object->presentParms.MultiSampleType,
1458 object->presentParms.MultiSampleQuality,
1459 TRUE /* Lockable */,
1460 &object->backBuffer[i],
1461 NULL /* pShared (always null)*/);
1462 if(hr == WINED3D_OK && object->backBuffer[i]) {
1463 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1464 } else {
1465 ERR("Cannot create new back buffer\n");
1466 goto error;
1468 ENTER_GL();
1469 glDrawBuffer(GL_BACK);
1470 checkGLcall("glDrawBuffer(GL_BACK)");
1471 LEAVE_GL();
1473 } else {
1474 object->backBuffer = NULL;
1476 /* Single buffering - draw to front buffer */
1477 ENTER_GL();
1478 glDrawBuffer(GL_FRONT);
1479 checkGLcall("glDrawBuffer(GL_FRONT)");
1480 LEAVE_GL();
1483 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1484 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1485 TRACE("Creating depth stencil buffer\n");
1486 if (This->depthStencilBuffer == NULL ) {
1487 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1488 parent,
1489 object->presentParms.BackBufferWidth,
1490 object->presentParms.BackBufferHeight,
1491 object->presentParms.AutoDepthStencilFormat,
1492 object->presentParms.MultiSampleType,
1493 object->presentParms.MultiSampleQuality,
1494 FALSE /* FIXME: Discard */,
1495 &This->depthStencilBuffer,
1496 NULL /* pShared (always null)*/ );
1497 if (This->depthStencilBuffer != NULL)
1498 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1501 /** TODO: A check on width, height and multisample types
1502 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1503 ****************************/
1504 object->wantsDepthStencilBuffer = TRUE;
1505 } else {
1506 object->wantsDepthStencilBuffer = FALSE;
1509 TRACE("Created swapchain %p\n", object);
1510 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1511 return WINED3D_OK;
1513 error:
1514 if (object->backBuffer) {
1515 int i;
1516 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1517 if(object->backBuffer[i]) {
1518 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1519 IUnknown_Release(bufferParent); /* once for the get parent */
1520 if (IUnknown_Release(bufferParent) > 0) {
1521 FIXME("(%p) Something's still holding the back buffer\n",This);
1525 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1526 object->backBuffer = NULL;
1528 if(object->context[0])
1529 DestroyContext(This, object->context[0]);
1530 if(object->frontBuffer) {
1531 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1532 IUnknown_Release(bufferParent); /* once for the get parent */
1533 if (IUnknown_Release(bufferParent) > 0) {
1534 FIXME("(%p) Something's still holding the front buffer\n",This);
1537 HeapFree(GetProcessHeap(), 0, object);
1538 return hr;
1541 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1542 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1544 TRACE("(%p)\n", This);
1546 return This->NumberOfSwapChains;
1549 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1550 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1551 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1553 if(iSwapChain < This->NumberOfSwapChains) {
1554 *pSwapChain = This->swapchains[iSwapChain];
1555 IWineD3DSwapChain_AddRef(*pSwapChain);
1556 TRACE("(%p) returning %p\n", This, *pSwapChain);
1557 return WINED3D_OK;
1558 } else {
1559 TRACE("Swapchain out of range\n");
1560 *pSwapChain = NULL;
1561 return WINED3DERR_INVALIDCALL;
1565 /*****
1566 * Vertex Declaration
1567 *****/
1568 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1569 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1571 IWineD3DVertexDeclarationImpl *object = NULL;
1572 HRESULT hr = WINED3D_OK;
1574 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1575 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1577 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1579 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1581 return hr;
1584 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1586 unsigned int idx, idx2;
1587 unsigned int offset;
1588 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1589 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1590 BOOL has_blend_idx = has_blend &&
1591 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1592 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1593 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1594 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1595 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1596 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1597 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1599 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1600 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1602 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1603 WINED3DVERTEXELEMENT *elements = NULL;
1605 unsigned int size;
1606 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1607 if (has_blend_idx) num_blends--;
1609 /* Compute declaration size */
1610 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1611 has_psize + has_diffuse + has_specular + num_textures + 1;
1613 /* convert the declaration */
1614 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1615 if (!elements)
1616 return 0;
1618 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1619 idx = 0;
1620 if (has_pos) {
1621 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1625 else {
1626 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1627 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1629 elements[idx].UsageIndex = 0;
1630 idx++;
1632 if (has_blend && (num_blends > 0)) {
1633 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1634 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1635 else
1636 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1637 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1638 elements[idx].UsageIndex = 0;
1639 idx++;
1641 if (has_blend_idx) {
1642 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1643 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1644 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1645 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1646 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1647 else
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1649 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1650 elements[idx].UsageIndex = 0;
1651 idx++;
1653 if (has_normal) {
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1655 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1656 elements[idx].UsageIndex = 0;
1657 idx++;
1659 if (has_psize) {
1660 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1661 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1662 elements[idx].UsageIndex = 0;
1663 idx++;
1665 if (has_diffuse) {
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 0;
1669 idx++;
1671 if (has_specular) {
1672 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1673 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1674 elements[idx].UsageIndex = 1;
1675 idx++;
1677 for (idx2 = 0; idx2 < num_textures; idx2++) {
1678 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1679 switch (numcoords) {
1680 case WINED3DFVF_TEXTUREFORMAT1:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1682 break;
1683 case WINED3DFVF_TEXTUREFORMAT2:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1685 break;
1686 case WINED3DFVF_TEXTUREFORMAT3:
1687 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1688 break;
1689 case WINED3DFVF_TEXTUREFORMAT4:
1690 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1691 break;
1693 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1694 elements[idx].UsageIndex = idx2;
1695 idx++;
1698 /* Now compute offsets, and initialize the rest of the fields */
1699 for (idx = 0, offset = 0; idx < size-1; idx++) {
1700 elements[idx].Stream = 0;
1701 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1702 elements[idx].Offset = offset;
1703 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1706 *ppVertexElements = elements;
1707 return size;
1710 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1711 WINED3DVERTEXELEMENT* elements = NULL;
1712 size_t size;
1713 DWORD hr;
1715 size = ConvertFvfToDeclaration(Fvf, &elements);
1716 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1718 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1719 HeapFree(GetProcessHeap(), 0, elements);
1720 if (hr != S_OK) return hr;
1722 return WINED3D_OK;
1725 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1726 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1728 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1729 HRESULT hr = WINED3D_OK;
1730 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1731 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1733 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1735 if (vertex_declaration) {
1736 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1739 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1741 if (WINED3D_OK != hr) {
1742 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1743 IWineD3DVertexShader_Release(*ppVertexShader);
1744 return WINED3DERR_INVALIDCALL;
1747 return WINED3D_OK;
1750 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1752 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1753 HRESULT hr = WINED3D_OK;
1755 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1756 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1757 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1758 if (WINED3D_OK == hr) {
1759 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1760 } else {
1761 WARN("(%p) : Failed to create pixel shader\n", This);
1764 return hr;
1767 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1769 IWineD3DPaletteImpl *object;
1770 HRESULT hr;
1771 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1773 /* Create the new object */
1774 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1775 if(!object) {
1776 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1777 return E_OUTOFMEMORY;
1780 object->lpVtbl = &IWineD3DPalette_Vtbl;
1781 object->ref = 1;
1782 object->Flags = Flags;
1783 object->parent = Parent;
1784 object->wineD3DDevice = This;
1785 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1787 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1789 if(!object->hpal) {
1790 HeapFree( GetProcessHeap(), 0, object);
1791 return E_OUTOFMEMORY;
1794 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1795 if(FAILED(hr)) {
1796 IWineD3DPalette_Release((IWineD3DPalette *) object);
1797 return hr;
1800 *Palette = (IWineD3DPalette *) object;
1802 return WINED3D_OK;
1805 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1807 IWineD3DSwapChainImpl *swapchain;
1808 HRESULT hr;
1809 DWORD state;
1811 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1812 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1814 /* TODO: Test if OpenGL is compiled in and loaded */
1816 TRACE("(%p) : Creating stateblock\n", This);
1817 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1818 hr = IWineD3DDevice_CreateStateBlock(iface,
1819 WINED3DSBT_INIT,
1820 (IWineD3DStateBlock **)&This->stateBlock,
1821 NULL);
1822 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1823 WARN("Failed to create stateblock\n");
1824 return hr;
1826 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1827 This->updateStateBlock = This->stateBlock;
1828 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1830 hr = allocate_shader_constants(This->updateStateBlock);
1831 if (WINED3D_OK != hr)
1832 return hr;
1834 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1835 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1836 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1838 /* Initialize the texture unit mapping to a 1:1 mapping */
1839 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1840 if (state < GL_LIMITS(fragment_samplers)) {
1841 This->texUnitMap[state] = state;
1842 This->rev_tex_unit_map[state] = state;
1843 } else {
1844 This->texUnitMap[state] = -1;
1845 This->rev_tex_unit_map[state] = -1;
1849 /* Setup the implicit swapchain */
1850 TRACE("Creating implicit swapchain\n");
1851 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1852 if (FAILED(hr) || !swapchain) {
1853 WARN("Failed to create implicit swapchain\n");
1854 return hr;
1857 This->NumberOfSwapChains = 1;
1858 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1859 if(!This->swapchains) {
1860 ERR("Out of memory!\n");
1861 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1862 return E_OUTOFMEMORY;
1864 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1866 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1868 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1869 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1870 This->render_targets[0] = swapchain->backBuffer[0];
1871 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1873 else {
1874 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1875 This->render_targets[0] = swapchain->frontBuffer;
1876 This->lastActiveRenderTarget = swapchain->frontBuffer;
1878 IWineD3DSurface_AddRef(This->render_targets[0]);
1879 This->activeContext = swapchain->context[0];
1880 This->lastThread = GetCurrentThreadId();
1882 /* Depth Stencil support */
1883 This->stencilBufferTarget = This->depthStencilBuffer;
1884 if (NULL != This->stencilBufferTarget) {
1885 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1888 /* Set up some starting GL setup */
1889 ENTER_GL();
1891 /* Setup all the devices defaults */
1892 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1893 #if 0
1894 IWineD3DImpl_CheckGraphicsMemory();
1895 #endif
1897 { /* Set a default viewport */
1898 WINED3DVIEWPORT vp;
1899 vp.X = 0;
1900 vp.Y = 0;
1901 vp.Width = pPresentationParameters->BackBufferWidth;
1902 vp.Height = pPresentationParameters->BackBufferHeight;
1903 vp.MinZ = 0.0f;
1904 vp.MaxZ = 1.0f;
1905 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1908 /* Initialize the current view state */
1909 This->view_ident = 1;
1910 This->contexts[0]->last_was_rhw = 0;
1911 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1912 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1914 switch(wined3d_settings.offscreen_rendering_mode) {
1915 case ORM_FBO:
1916 case ORM_PBUFFER:
1917 This->offscreenBuffer = GL_BACK;
1918 break;
1920 case ORM_BACKBUFFER:
1922 if(GL_LIMITS(aux_buffers) > 0) {
1923 TRACE("Using auxilliary buffer for offscreen rendering\n");
1924 This->offscreenBuffer = GL_AUX0;
1925 } else {
1926 TRACE("Using back buffer for offscreen rendering\n");
1927 This->offscreenBuffer = GL_BACK;
1932 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1933 LEAVE_GL();
1935 /* Clear the screen */
1936 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1937 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1938 0x00, 1.0, 0);
1940 This->d3d_initialized = TRUE;
1941 return WINED3D_OK;
1944 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1946 int sampler;
1947 UINT i;
1948 TRACE("(%p)\n", This);
1950 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1952 /* I don't think that the interface guarants that the device is destroyed from the same thread
1953 * it was created. Thus make sure a context is active for the glDelete* calls
1955 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1957 TRACE("Deleting high order patches\n");
1958 for(i = 0; i < PATCHMAP_SIZE; i++) {
1959 struct list *e1, *e2;
1960 struct WineD3DRectPatch *patch;
1961 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1962 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1963 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1967 /* Delete the pbuffer context if there is any */
1968 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1970 /* Delete the mouse cursor texture */
1971 if(This->cursorTexture) {
1972 ENTER_GL();
1973 glDeleteTextures(1, &This->cursorTexture);
1974 LEAVE_GL();
1975 This->cursorTexture = 0;
1978 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1979 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1981 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1982 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1985 /* Release the update stateblock */
1986 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1987 if(This->updateStateBlock != This->stateBlock)
1988 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1990 This->updateStateBlock = NULL;
1992 { /* because were not doing proper internal refcounts releasing the primary state block
1993 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1994 to set this->stateBlock = NULL; first */
1995 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1996 This->stateBlock = NULL;
1998 /* Release the stateblock */
1999 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2000 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2004 /* Release the buffers (with sanity checks)*/
2005 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2006 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2007 if(This->depthStencilBuffer != This->stencilBufferTarget)
2008 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2010 This->stencilBufferTarget = NULL;
2012 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2013 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2014 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2016 TRACE("Setting rendertarget to NULL\n");
2017 This->render_targets[0] = NULL;
2019 if (This->depthStencilBuffer) {
2020 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2021 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2023 This->depthStencilBuffer = NULL;
2026 for(i=0; i < This->NumberOfSwapChains; i++) {
2027 TRACE("Releasing the implicit swapchain %d\n", i);
2028 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2029 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2033 HeapFree(GetProcessHeap(), 0, This->swapchains);
2034 This->swapchains = NULL;
2035 This->NumberOfSwapChains = 0;
2037 HeapFree(GetProcessHeap(), 0, This->render_targets);
2038 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2039 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2040 This->render_targets = NULL;
2041 This->fbo_color_attachments = NULL;
2042 This->draw_buffers = NULL;
2045 This->d3d_initialized = FALSE;
2046 return WINED3D_OK;
2049 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2051 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2053 /* Setup the window for fullscreen mode */
2054 if(fullscreen && !This->ddraw_fullscreen) {
2055 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2056 } else if(!fullscreen && This->ddraw_fullscreen) {
2057 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2060 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2061 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2062 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2063 * separately.
2065 This->ddraw_fullscreen = fullscreen;
2068 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2069 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2070 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2072 * There is no way to deactivate thread safety once it is enabled
2074 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2077 /*For now just store the flag(needed in case of ddraw) */
2078 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2080 return;
2083 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2084 DEVMODEW devmode;
2085 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2086 LONG ret;
2087 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2088 RECT clip_rc;
2090 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2092 /* Resize the screen even without a window:
2093 * The app could have unset it with SetCooperativeLevel, but not called
2094 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2095 * but we don't have any hwnd
2098 memset(&devmode, 0, sizeof(devmode));
2099 devmode.dmSize = sizeof(devmode);
2100 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2101 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2102 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2103 devmode.dmPelsWidth = pMode->Width;
2104 devmode.dmPelsHeight = pMode->Height;
2106 devmode.dmDisplayFrequency = pMode->RefreshRate;
2107 if (pMode->RefreshRate != 0) {
2108 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2111 /* Only change the mode if necessary */
2112 if( (This->ddraw_width == pMode->Width) &&
2113 (This->ddraw_height == pMode->Height) &&
2114 (This->ddraw_format == pMode->Format) &&
2115 (pMode->RefreshRate == 0) ) {
2116 return WINED3D_OK;
2119 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2120 if (ret != DISP_CHANGE_SUCCESSFUL) {
2121 if(devmode.dmDisplayFrequency != 0) {
2122 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2123 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2124 devmode.dmDisplayFrequency = 0;
2125 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2127 if(ret != DISP_CHANGE_SUCCESSFUL) {
2128 return WINED3DERR_NOTAVAILABLE;
2132 /* Store the new values */
2133 This->ddraw_width = pMode->Width;
2134 This->ddraw_height = pMode->Height;
2135 This->ddraw_format = pMode->Format;
2137 /* Only do this with a window of course */
2138 if(This->ddraw_window)
2139 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2141 /* And finally clip mouse to our screen */
2142 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2143 ClipCursor(&clip_rc);
2145 return WINED3D_OK;
2148 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2150 *ppD3D= This->wineD3D;
2151 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2152 IWineD3D_AddRef(*ppD3D);
2153 return WINED3D_OK;
2156 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2157 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2158 * into the video ram as possible and seeing how many fit
2159 * you can also get the correct initial value from nvidia and ATI's driver via X
2160 * texture memory is video memory + AGP memory
2161 *******************/
2162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2163 static BOOL showfixmes = TRUE;
2164 if (showfixmes) {
2165 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2166 (wined3d_settings.emulated_textureram/(1024*1024)),
2167 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2168 showfixmes = FALSE;
2170 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2171 (wined3d_settings.emulated_textureram/(1024*1024)),
2172 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2173 /* return simulated texture memory left */
2174 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2179 /*****
2180 * Get / Set FVF
2181 *****/
2182 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2185 /* Update the current state block */
2186 This->updateStateBlock->changed.fvf = TRUE;
2188 if(This->updateStateBlock->fvf == fvf) {
2189 TRACE("Application is setting the old fvf over, nothing to do\n");
2190 return WINED3D_OK;
2193 This->updateStateBlock->fvf = fvf;
2194 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2195 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2196 return WINED3D_OK;
2200 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2202 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2203 *pfvf = This->stateBlock->fvf;
2204 return WINED3D_OK;
2207 /*****
2208 * Get / Set Stream Source
2209 *****/
2210 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2212 IWineD3DVertexBuffer *oldSrc;
2214 if (StreamNumber >= MAX_STREAMS) {
2215 WARN("Stream out of range %d\n", StreamNumber);
2216 return WINED3DERR_INVALIDCALL;
2219 oldSrc = This->stateBlock->streamSource[StreamNumber];
2220 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2222 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2224 if(oldSrc == pStreamData &&
2225 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2226 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2227 TRACE("Application is setting the old values over, nothing to do\n");
2228 return WINED3D_OK;
2231 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2232 if (pStreamData) {
2233 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2234 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2237 /* Handle recording of state blocks */
2238 if (This->isRecordingState) {
2239 TRACE("Recording... not performing anything\n");
2240 return WINED3D_OK;
2243 /* Need to do a getParent and pass the reffs up */
2244 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2245 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2246 so for now, just count internally */
2247 if (pStreamData != NULL) {
2248 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2249 InterlockedIncrement(&vbImpl->bindCount);
2250 IWineD3DVertexBuffer_AddRef(pStreamData);
2252 if (oldSrc != NULL) {
2253 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2254 IWineD3DVertexBuffer_Release(oldSrc);
2257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2259 return WINED3D_OK;
2262 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2265 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2266 This->stateBlock->streamSource[StreamNumber],
2267 This->stateBlock->streamOffset[StreamNumber],
2268 This->stateBlock->streamStride[StreamNumber]);
2270 if (StreamNumber >= MAX_STREAMS) {
2271 WARN("Stream out of range %d\n", StreamNumber);
2272 return WINED3DERR_INVALIDCALL;
2274 *pStream = This->stateBlock->streamSource[StreamNumber];
2275 *pStride = This->stateBlock->streamStride[StreamNumber];
2276 if (pOffset) {
2277 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2280 if (*pStream != NULL) {
2281 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2283 return WINED3D_OK;
2286 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2288 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2289 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2291 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2292 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2294 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2295 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2297 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2298 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2302 return WINED3D_OK;
2305 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2308 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2309 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2311 TRACE("(%p) : returning %d\n", This, *Divider);
2313 return WINED3D_OK;
2316 /*****
2317 * Get / Set & Multiply Transform
2318 *****/
2319 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2322 /* Most of this routine, comments included copied from ddraw tree initially: */
2323 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2325 /* Handle recording of state blocks */
2326 if (This->isRecordingState) {
2327 TRACE("Recording... not performing anything\n");
2328 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2329 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2330 return WINED3D_OK;
2334 * If the new matrix is the same as the current one,
2335 * we cut off any further processing. this seems to be a reasonable
2336 * optimization because as was noticed, some apps (warcraft3 for example)
2337 * tend towards setting the same matrix repeatedly for some reason.
2339 * From here on we assume that the new matrix is different, wherever it matters.
2341 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2342 TRACE("The app is setting the same matrix over again\n");
2343 return WINED3D_OK;
2344 } else {
2345 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2349 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2350 where ViewMat = Camera space, WorldMat = world space.
2352 In OpenGL, camera and world space is combined into GL_MODELVIEW
2353 matrix. The Projection matrix stay projection matrix.
2356 /* Capture the times we can just ignore the change for now */
2357 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2358 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2359 /* Handled by the state manager */
2362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2363 return WINED3D_OK;
2366 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2368 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2369 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2370 return WINED3D_OK;
2373 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2374 WINED3DMATRIX *mat = NULL;
2375 WINED3DMATRIX temp;
2377 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2378 * below means it will be recorded in a state block change, but it
2379 * works regardless where it is recorded.
2380 * If this is found to be wrong, change to StateBlock.
2382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2383 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2385 if (State < HIGHEST_TRANSFORMSTATE)
2387 mat = &This->updateStateBlock->transforms[State];
2388 } else {
2389 FIXME("Unhandled transform state!!\n");
2392 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2394 /* Apply change via set transform - will reapply to eg. lights this way */
2395 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2398 /*****
2399 * Get / Set Light
2400 *****/
2401 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2402 you can reference any indexes you want as long as that number max are enabled at any
2403 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2404 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2405 but when recording, just build a chain pretty much of commands to be replayed. */
2407 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2408 float rho;
2409 PLIGHTINFOEL *object = NULL;
2410 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2411 struct list *e;
2413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2414 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2416 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2417 * the gl driver.
2419 if(!pLight) {
2420 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2421 return WINED3DERR_INVALIDCALL;
2424 switch(pLight->Type) {
2425 case WINED3DLIGHT_POINT:
2426 case WINED3DLIGHT_SPOT:
2427 case WINED3DLIGHT_PARALLELPOINT:
2428 case WINED3DLIGHT_GLSPOT:
2429 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2430 * most wanted
2432 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2433 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2434 return WINED3DERR_INVALIDCALL;
2436 break;
2438 case WINED3DLIGHT_DIRECTIONAL:
2439 /* Ignores attenuation */
2440 break;
2442 default:
2443 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2444 return WINED3DERR_INVALIDCALL;
2447 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2448 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2449 if(object->OriginalIndex == Index) break;
2450 object = NULL;
2453 if(!object) {
2454 TRACE("Adding new light\n");
2455 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2456 if(!object) {
2457 ERR("Out of memory error when allocating a light\n");
2458 return E_OUTOFMEMORY;
2460 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2461 object->glIndex = -1;
2462 object->OriginalIndex = Index;
2463 object->changed = TRUE;
2466 /* Initialize the object */
2467 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,
2468 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2469 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2470 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2471 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2472 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2473 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2475 /* Save away the information */
2476 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2478 switch (pLight->Type) {
2479 case WINED3DLIGHT_POINT:
2480 /* Position */
2481 object->lightPosn[0] = pLight->Position.x;
2482 object->lightPosn[1] = pLight->Position.y;
2483 object->lightPosn[2] = pLight->Position.z;
2484 object->lightPosn[3] = 1.0f;
2485 object->cutoff = 180.0f;
2486 /* FIXME: Range */
2487 break;
2489 case WINED3DLIGHT_DIRECTIONAL:
2490 /* Direction */
2491 object->lightPosn[0] = -pLight->Direction.x;
2492 object->lightPosn[1] = -pLight->Direction.y;
2493 object->lightPosn[2] = -pLight->Direction.z;
2494 object->lightPosn[3] = 0.0;
2495 object->exponent = 0.0f;
2496 object->cutoff = 180.0f;
2497 break;
2499 case WINED3DLIGHT_SPOT:
2500 /* Position */
2501 object->lightPosn[0] = pLight->Position.x;
2502 object->lightPosn[1] = pLight->Position.y;
2503 object->lightPosn[2] = pLight->Position.z;
2504 object->lightPosn[3] = 1.0;
2506 /* Direction */
2507 object->lightDirn[0] = pLight->Direction.x;
2508 object->lightDirn[1] = pLight->Direction.y;
2509 object->lightDirn[2] = pLight->Direction.z;
2510 object->lightDirn[3] = 1.0;
2513 * opengl-ish and d3d-ish spot lights use too different models for the
2514 * light "intensity" as a function of the angle towards the main light direction,
2515 * so we only can approximate very roughly.
2516 * however spot lights are rather rarely used in games (if ever used at all).
2517 * furthermore if still used, probably nobody pays attention to such details.
2519 if (pLight->Falloff == 0) {
2520 rho = 6.28f;
2521 } else {
2522 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2524 if (rho < 0.0001) rho = 0.0001f;
2525 object->exponent = -0.3/log(cos(rho/2));
2526 if (object->exponent > 128.0) {
2527 object->exponent = 128.0;
2529 object->cutoff = pLight->Phi*90/M_PI;
2531 /* FIXME: Range */
2532 break;
2534 default:
2535 FIXME("Unrecognized light type %d\n", pLight->Type);
2538 /* Update the live definitions if the light is currently assigned a glIndex */
2539 if (object->glIndex != -1 && !This->isRecordingState) {
2540 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2542 return WINED3D_OK;
2545 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2546 PLIGHTINFOEL *lightInfo = NULL;
2547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2549 struct list *e;
2550 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2552 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2553 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2554 if(lightInfo->OriginalIndex == Index) break;
2555 lightInfo = NULL;
2558 if (lightInfo == NULL) {
2559 TRACE("Light information requested but light not defined\n");
2560 return WINED3DERR_INVALIDCALL;
2563 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2564 return WINED3D_OK;
2567 /*****
2568 * Get / Set Light Enable
2569 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2570 *****/
2571 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2572 PLIGHTINFOEL *lightInfo = NULL;
2573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2574 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2575 struct list *e;
2576 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2578 /* Tests show true = 128...not clear why */
2579 Enable = Enable? 128: 0;
2581 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2582 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2583 if(lightInfo->OriginalIndex == Index) break;
2584 lightInfo = NULL;
2586 TRACE("Found light: %p\n", lightInfo);
2588 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2589 if (lightInfo == NULL) {
2591 TRACE("Light enabled requested but light not defined, so defining one!\n");
2592 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2594 /* Search for it again! Should be fairly quick as near head of list */
2595 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2596 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2597 if(lightInfo->OriginalIndex == Index) break;
2598 lightInfo = NULL;
2600 if (lightInfo == NULL) {
2601 FIXME("Adding default lights has failed dismally\n");
2602 return WINED3DERR_INVALIDCALL;
2606 lightInfo->enabledChanged = TRUE;
2607 if(!Enable) {
2608 if(lightInfo->glIndex != -1) {
2609 if(!This->isRecordingState) {
2610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2613 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2614 lightInfo->glIndex = -1;
2615 } else {
2616 TRACE("Light already disabled, nothing to do\n");
2618 } else {
2619 if (lightInfo->glIndex != -1) {
2620 /* nop */
2621 TRACE("Nothing to do as light was enabled\n");
2622 } else {
2623 int i;
2624 /* Find a free gl light */
2625 for(i = 0; i < This->maxConcurrentLights; i++) {
2626 if(This->stateBlock->activeLights[i] == NULL) {
2627 This->stateBlock->activeLights[i] = lightInfo;
2628 lightInfo->glIndex = i;
2629 break;
2632 if(lightInfo->glIndex == -1) {
2633 ERR("Too many concurrently active lights\n");
2634 return WINED3DERR_INVALIDCALL;
2637 /* i == lightInfo->glIndex */
2638 if(!This->isRecordingState) {
2639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2649 PLIGHTINFOEL *lightInfo = NULL;
2650 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2651 struct list *e;
2652 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2653 TRACE("(%p) : for idx(%d)\n", This, Index);
2655 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2656 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2657 if(lightInfo->OriginalIndex == Index) break;
2658 lightInfo = NULL;
2661 if (lightInfo == NULL) {
2662 TRACE("Light enabled state requested but light not defined\n");
2663 return WINED3DERR_INVALIDCALL;
2665 /* true is 128 according to SetLightEnable */
2666 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2667 return WINED3D_OK;
2670 /*****
2671 * Get / Set Clip Planes
2672 *****/
2673 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2675 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2677 /* Validate Index */
2678 if (Index >= GL_LIMITS(clipplanes)) {
2679 TRACE("Application has requested clipplane this device doesn't support\n");
2680 return WINED3DERR_INVALIDCALL;
2683 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2685 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2686 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2687 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2688 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2689 TRACE("Application is setting old values over, nothing to do\n");
2690 return WINED3D_OK;
2693 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2694 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2695 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2696 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2698 /* Handle recording of state blocks */
2699 if (This->isRecordingState) {
2700 TRACE("Recording... not performing anything\n");
2701 return WINED3D_OK;
2704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2706 return WINED3D_OK;
2709 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2711 TRACE("(%p) : for idx %d\n", This, Index);
2713 /* Validate Index */
2714 if (Index >= GL_LIMITS(clipplanes)) {
2715 TRACE("Application has requested clipplane this device doesn't support\n");
2716 return WINED3DERR_INVALIDCALL;
2719 pPlane[0] = This->stateBlock->clipplane[Index][0];
2720 pPlane[1] = This->stateBlock->clipplane[Index][1];
2721 pPlane[2] = This->stateBlock->clipplane[Index][2];
2722 pPlane[3] = This->stateBlock->clipplane[Index][3];
2723 return WINED3D_OK;
2726 /*****
2727 * Get / Set Clip Plane Status
2728 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2729 *****/
2730 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2732 FIXME("(%p) : stub\n", This);
2733 if (NULL == pClipStatus) {
2734 return WINED3DERR_INVALIDCALL;
2736 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2737 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2738 return WINED3D_OK;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 FIXME("(%p) : stub\n", This);
2744 if (NULL == pClipStatus) {
2745 return WINED3DERR_INVALIDCALL;
2747 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2748 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2749 return WINED3D_OK;
2752 /*****
2753 * Get / Set Material
2754 *****/
2755 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 This->updateStateBlock->changed.material = TRUE;
2759 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2761 /* Handle recording of state blocks */
2762 if (This->isRecordingState) {
2763 TRACE("Recording... not performing anything\n");
2764 return WINED3D_OK;
2767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2768 return WINED3D_OK;
2771 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2774 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2775 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2776 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2777 pMaterial->Ambient.b, pMaterial->Ambient.a);
2778 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2779 pMaterial->Specular.b, pMaterial->Specular.a);
2780 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2781 pMaterial->Emissive.b, pMaterial->Emissive.a);
2782 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2784 return WINED3D_OK;
2787 /*****
2788 * Get / Set Indices
2789 *****/
2790 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2792 IWineD3DIndexBuffer *oldIdxs;
2794 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2795 oldIdxs = This->updateStateBlock->pIndexData;
2797 This->updateStateBlock->changed.indices = TRUE;
2798 This->updateStateBlock->pIndexData = pIndexData;
2800 /* Handle recording of state blocks */
2801 if (This->isRecordingState) {
2802 TRACE("Recording... not performing anything\n");
2803 return WINED3D_OK;
2806 if(oldIdxs != pIndexData) {
2807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2808 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2809 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2811 return WINED3D_OK;
2814 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 *ppIndexData = This->stateBlock->pIndexData;
2819 /* up ref count on ppindexdata */
2820 if (*ppIndexData) {
2821 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2822 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2823 }else{
2824 TRACE("(%p) No index data set\n", This);
2826 TRACE("Returning %p\n", *ppIndexData);
2828 return WINED3D_OK;
2831 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2832 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 TRACE("(%p)->(%d)\n", This, BaseIndex);
2836 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2837 TRACE("Application is setting the old value over, nothing to do\n");
2838 return WINED3D_OK;
2841 This->updateStateBlock->baseVertexIndex = BaseIndex;
2843 if (This->isRecordingState) {
2844 TRACE("Recording... not performing anything\n");
2845 return WINED3D_OK;
2847 /* The base vertex index affects the stream sources */
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2849 return WINED3D_OK;
2852 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2854 TRACE("(%p) : base_index %p\n", This, base_index);
2856 *base_index = This->stateBlock->baseVertexIndex;
2858 TRACE("Returning %u\n", *base_index);
2860 return WINED3D_OK;
2863 /*****
2864 * Get / Set Viewports
2865 *****/
2866 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2869 TRACE("(%p)\n", This);
2870 This->updateStateBlock->changed.viewport = TRUE;
2871 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2873 /* Handle recording of state blocks */
2874 if (This->isRecordingState) {
2875 TRACE("Recording... not performing anything\n");
2876 return WINED3D_OK;
2879 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2880 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2883 return WINED3D_OK;
2887 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 TRACE("(%p)\n", This);
2890 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2891 return WINED3D_OK;
2894 /*****
2895 * Get / Set Render States
2896 * TODO: Verify against dx9 definitions
2897 *****/
2898 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2901 DWORD oldValue = This->stateBlock->renderState[State];
2903 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2905 This->updateStateBlock->changed.renderState[State] = TRUE;
2906 This->updateStateBlock->renderState[State] = Value;
2908 /* Handle recording of state blocks */
2909 if (This->isRecordingState) {
2910 TRACE("Recording... not performing anything\n");
2911 return WINED3D_OK;
2914 /* Compared here and not before the assignment to allow proper stateblock recording */
2915 if(Value == oldValue) {
2916 TRACE("Application is setting the old value over, nothing to do\n");
2917 } else {
2918 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2921 return WINED3D_OK;
2924 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2926 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2927 *pValue = This->stateBlock->renderState[State];
2928 return WINED3D_OK;
2931 /*****
2932 * Get / Set Sampler States
2933 * TODO: Verify against dx9 definitions
2934 *****/
2936 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 DWORD oldValue;
2940 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2941 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2943 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2944 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2948 * SetSampler is designed to allow for more than the standard up to 8 textures
2949 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2950 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2952 * http://developer.nvidia.com/object/General_FAQ.html#t6
2954 * There are two new settings for GForce
2955 * the sampler one:
2956 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2957 * and the texture one:
2958 * GL_MAX_TEXTURE_COORDS_ARB.
2959 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2960 ******************/
2962 oldValue = This->stateBlock->samplerState[Sampler][Type];
2963 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2964 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2966 /* Handle recording of state blocks */
2967 if (This->isRecordingState) {
2968 TRACE("Recording... not performing anything\n");
2969 return WINED3D_OK;
2972 if(oldValue == Value) {
2973 TRACE("Application is setting the old value over, nothing to do\n");
2974 return WINED3D_OK;
2977 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2979 return WINED3D_OK;
2982 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2985 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2986 This, Sampler, debug_d3dsamplerstate(Type), Type);
2988 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2989 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2992 *Value = This->stateBlock->samplerState[Sampler][Type];
2993 TRACE("(%p) : Returning %#x\n", This, *Value);
2995 return WINED3D_OK;
2998 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 This->updateStateBlock->changed.scissorRect = TRUE;
3002 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3003 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3004 return WINED3D_OK;
3006 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3008 if(This->isRecordingState) {
3009 TRACE("Recording... not performing anything\n");
3010 return WINED3D_OK;
3013 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3015 return WINED3D_OK;
3018 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3022 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3023 return WINED3D_OK;
3026 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3028 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3030 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3032 This->updateStateBlock->vertexDecl = pDecl;
3033 This->updateStateBlock->changed.vertexDecl = TRUE;
3035 if (This->isRecordingState) {
3036 TRACE("Recording... not performing anything\n");
3037 return WINED3D_OK;
3038 } else if(pDecl == oldDecl) {
3039 /* Checked after the assignment to allow proper stateblock recording */
3040 TRACE("Application is setting the old declaration over, nothing to do\n");
3041 return WINED3D_OK;
3044 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3045 return WINED3D_OK;
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3051 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3053 *ppDecl = This->stateBlock->vertexDecl;
3054 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3055 return WINED3D_OK;
3058 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3060 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3062 This->updateStateBlock->vertexShader = pShader;
3063 This->updateStateBlock->changed.vertexShader = TRUE;
3065 if (This->isRecordingState) {
3066 TRACE("Recording... not performing anything\n");
3067 return WINED3D_OK;
3068 } else if(oldShader == pShader) {
3069 /* Checked here to allow proper stateblock recording */
3070 TRACE("App is setting the old shader over, nothing to do\n");
3071 return WINED3D_OK;
3074 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3076 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3078 return WINED3D_OK;
3081 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 if (NULL == ppShader) {
3085 return WINED3DERR_INVALIDCALL;
3087 *ppShader = This->stateBlock->vertexShader;
3088 if( NULL != *ppShader)
3089 IWineD3DVertexShader_AddRef(*ppShader);
3091 TRACE("(%p) : returning %p\n", This, *ppShader);
3092 return WINED3D_OK;
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3096 IWineD3DDevice *iface,
3097 UINT start,
3098 CONST BOOL *srcData,
3099 UINT count) {
3101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3102 int i, cnt = min(count, MAX_CONST_B - start);
3104 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3105 iface, srcData, start, count);
3107 if (srcData == NULL || cnt < 0)
3108 return WINED3DERR_INVALIDCALL;
3110 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3111 for (i = 0; i < cnt; i++)
3112 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3114 for (i = start; i < cnt + start; ++i) {
3115 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3118 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3120 return WINED3D_OK;
3123 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3124 IWineD3DDevice *iface,
3125 UINT start,
3126 BOOL *dstData,
3127 UINT count) {
3129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3130 int cnt = min(count, MAX_CONST_B - start);
3132 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3133 iface, dstData, start, count);
3135 if (dstData == NULL || cnt < 0)
3136 return WINED3DERR_INVALIDCALL;
3138 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3139 return WINED3D_OK;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3143 IWineD3DDevice *iface,
3144 UINT start,
3145 CONST int *srcData,
3146 UINT count) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 int i, cnt = min(count, MAX_CONST_I - start);
3151 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3152 iface, srcData, start, count);
3154 if (srcData == NULL || cnt < 0)
3155 return WINED3DERR_INVALIDCALL;
3157 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3158 for (i = 0; i < cnt; i++)
3159 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3160 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3162 for (i = start; i < cnt + start; ++i) {
3163 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3168 return WINED3D_OK;
3171 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3172 IWineD3DDevice *iface,
3173 UINT start,
3174 int *dstData,
3175 UINT count) {
3177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3178 int cnt = min(count, MAX_CONST_I - start);
3180 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3181 iface, dstData, start, count);
3183 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3184 return WINED3DERR_INVALIDCALL;
3186 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3191 IWineD3DDevice *iface,
3192 UINT start,
3193 CONST float *srcData,
3194 UINT count) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3197 int i;
3199 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3200 iface, srcData, start, count);
3202 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3203 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3204 return WINED3DERR_INVALIDCALL;
3206 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3207 if(TRACE_ON(d3d)) {
3208 for (i = 0; i < count; i++)
3209 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3210 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3213 for (i = start; i < count + start; ++i) {
3214 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3215 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3216 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3217 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3218 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3220 ptr->idx[ptr->count++] = i;
3221 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3227 return WINED3D_OK;
3230 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3231 IWineD3DDevice *iface,
3232 UINT start,
3233 float *dstData,
3234 UINT count) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3239 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3240 iface, dstData, start, count);
3242 if (dstData == NULL || cnt < 0)
3243 return WINED3DERR_INVALIDCALL;
3245 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3246 return WINED3D_OK;
3249 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3250 DWORD i;
3251 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3256 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3257 int i = This->rev_tex_unit_map[unit];
3258 int j = This->texUnitMap[stage];
3260 This->texUnitMap[stage] = unit;
3261 if (i != -1 && i != stage) {
3262 This->texUnitMap[i] = -1;
3265 This->rev_tex_unit_map[unit] = stage;
3266 if (j != -1 && j != unit) {
3267 This->rev_tex_unit_map[j] = -1;
3271 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3272 int i;
3274 for (i = 0; i < MAX_TEXTURES; ++i) {
3275 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3276 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3277 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3278 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3279 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3280 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3281 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3282 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3284 if (color_op == WINED3DTOP_DISABLE) {
3285 /* Not used, and disable higher stages */
3286 while (i < MAX_TEXTURES) {
3287 This->fixed_function_usage_map[i] = FALSE;
3288 ++i;
3290 break;
3293 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3294 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3295 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3296 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3297 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3298 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3299 This->fixed_function_usage_map[i] = TRUE;
3300 } else {
3301 This->fixed_function_usage_map[i] = FALSE;
3304 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3305 This->fixed_function_usage_map[i+1] = TRUE;
3310 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3311 int i, tex;
3313 device_update_fixed_function_usage_map(This);
3315 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3316 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3317 if (!This->fixed_function_usage_map[i]) continue;
3319 if (This->texUnitMap[i] != i) {
3320 device_map_stage(This, i, i);
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3322 markTextureStagesDirty(This, i);
3325 return;
3328 /* Now work out the mapping */
3329 tex = 0;
3330 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3331 if (!This->fixed_function_usage_map[i]) continue;
3333 if (This->texUnitMap[i] != tex) {
3334 device_map_stage(This, i, tex);
3335 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3336 markTextureStagesDirty(This, i);
3339 ++tex;
3343 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3344 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3345 int i;
3347 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3348 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3349 device_map_stage(This, i, i);
3350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3351 if (i < MAX_TEXTURES) {
3352 markTextureStagesDirty(This, i);
3358 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3359 int current_mapping = This->rev_tex_unit_map[unit];
3361 if (current_mapping == -1) {
3362 /* Not currently used */
3363 return TRUE;
3366 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3367 /* Used by a fragment sampler */
3369 if (!pshader_sampler_tokens) {
3370 /* No pixel shader, check fixed function */
3371 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3374 /* Pixel shader, check the shader's sampler map */
3375 return !pshader_sampler_tokens[current_mapping];
3378 /* Used by a vertex sampler */
3379 return !vshader_sampler_tokens[current_mapping];
3382 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3383 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3384 DWORD *pshader_sampler_tokens = NULL;
3385 int start = GL_LIMITS(combined_samplers) - 1;
3386 int i;
3388 if (ps) {
3389 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3391 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3392 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3393 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3396 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3397 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3398 if (vshader_sampler_tokens[i]) {
3399 if (This->texUnitMap[vsampler_idx] != -1) {
3400 /* Already mapped somewhere */
3401 continue;
3404 while (start >= 0) {
3405 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3406 device_map_stage(This, vsampler_idx, start);
3407 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3409 --start;
3410 break;
3413 --start;
3419 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3420 BOOL vs = use_vs(This);
3421 BOOL ps = use_ps(This);
3423 * Rules are:
3424 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3425 * that would be really messy and require shader recompilation
3426 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3427 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3429 if (ps) {
3430 device_map_psamplers(This);
3431 } else {
3432 device_map_fixed_function_samplers(This);
3435 if (vs) {
3436 device_map_vsamplers(This, ps);
3440 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3441 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3442 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3443 This->updateStateBlock->pixelShader = pShader;
3444 This->updateStateBlock->changed.pixelShader = TRUE;
3446 /* Handle recording of state blocks */
3447 if (This->isRecordingState) {
3448 TRACE("Recording... not performing anything\n");
3451 if (This->isRecordingState) {
3452 TRACE("Recording... not performing anything\n");
3453 return WINED3D_OK;
3456 if(pShader == oldShader) {
3457 TRACE("App is setting the old pixel shader over, nothing to do\n");
3458 return WINED3D_OK;
3461 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3462 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3464 return WINED3D_OK;
3467 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3470 if (NULL == ppShader) {
3471 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3472 return WINED3DERR_INVALIDCALL;
3475 *ppShader = This->stateBlock->pixelShader;
3476 if (NULL != *ppShader) {
3477 IWineD3DPixelShader_AddRef(*ppShader);
3479 TRACE("(%p) : returning %p\n", This, *ppShader);
3480 return WINED3D_OK;
3483 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3484 IWineD3DDevice *iface,
3485 UINT start,
3486 CONST BOOL *srcData,
3487 UINT count) {
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 int i, cnt = min(count, MAX_CONST_B - start);
3492 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3493 iface, srcData, start, count);
3495 if (srcData == NULL || cnt < 0)
3496 return WINED3DERR_INVALIDCALL;
3498 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3499 for (i = 0; i < cnt; i++)
3500 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3502 for (i = start; i < cnt + start; ++i) {
3503 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3508 return WINED3D_OK;
3511 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3512 IWineD3DDevice *iface,
3513 UINT start,
3514 BOOL *dstData,
3515 UINT count) {
3517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3518 int cnt = min(count, MAX_CONST_B - start);
3520 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3521 iface, dstData, start, count);
3523 if (dstData == NULL || cnt < 0)
3524 return WINED3DERR_INVALIDCALL;
3526 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3527 return WINED3D_OK;
3530 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3531 IWineD3DDevice *iface,
3532 UINT start,
3533 CONST int *srcData,
3534 UINT count) {
3536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3537 int i, cnt = min(count, MAX_CONST_I - start);
3539 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3540 iface, srcData, start, count);
3542 if (srcData == NULL || cnt < 0)
3543 return WINED3DERR_INVALIDCALL;
3545 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3546 for (i = 0; i < cnt; i++)
3547 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3548 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3550 for (i = start; i < cnt + start; ++i) {
3551 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3556 return WINED3D_OK;
3559 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3560 IWineD3DDevice *iface,
3561 UINT start,
3562 int *dstData,
3563 UINT count) {
3565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3566 int cnt = min(count, MAX_CONST_I - start);
3568 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3569 iface, dstData, start, count);
3571 if (dstData == NULL || cnt < 0)
3572 return WINED3DERR_INVALIDCALL;
3574 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3575 return WINED3D_OK;
3578 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3579 IWineD3DDevice *iface,
3580 UINT start,
3581 CONST float *srcData,
3582 UINT count) {
3584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3585 int i;
3587 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3588 iface, srcData, start, count);
3590 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3591 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3592 return WINED3DERR_INVALIDCALL;
3594 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3595 if(TRACE_ON(d3d)) {
3596 for (i = 0; i < count; i++)
3597 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3598 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3601 for (i = start; i < count + start; ++i) {
3602 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3603 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3604 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3605 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3606 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3608 ptr->idx[ptr->count++] = i;
3609 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3615 return WINED3D_OK;
3618 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3619 IWineD3DDevice *iface,
3620 UINT start,
3621 float *dstData,
3622 UINT count) {
3624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3625 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3627 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3628 iface, dstData, start, count);
3630 if (dstData == NULL || cnt < 0)
3631 return WINED3DERR_INVALIDCALL;
3633 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3634 return WINED3D_OK;
3637 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3638 static HRESULT
3639 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3640 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3641 unsigned int i;
3642 DWORD DestFVF = dest->fvf;
3643 WINED3DVIEWPORT vp;
3644 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3645 BOOL doClip;
3646 int numTextures;
3648 if (lpStrideData->u.s.normal.lpData) {
3649 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3652 if (lpStrideData->u.s.position.lpData == NULL) {
3653 ERR("Source has no position mask\n");
3654 return WINED3DERR_INVALIDCALL;
3657 /* We might access VBOs from this code, so hold the lock */
3658 ENTER_GL();
3660 if (dest->resource.allocatedMemory == NULL) {
3661 /* This may happen if we do direct locking into a vbo. Unlikely,
3662 * but theoretically possible(ddraw processvertices test)
3664 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3665 if(!dest->resource.allocatedMemory) {
3666 LEAVE_GL();
3667 ERR("Out of memory\n");
3668 return E_OUTOFMEMORY;
3670 if(dest->vbo) {
3671 void *src;
3672 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3673 checkGLcall("glBindBufferARB");
3674 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3675 if(src) {
3676 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3678 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3679 checkGLcall("glUnmapBufferARB");
3683 /* Get a pointer into the destination vbo(create one if none exists) and
3684 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3686 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3687 CreateVBO(dest);
3690 if(dest->vbo) {
3691 unsigned char extrabytes = 0;
3692 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3693 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3694 * this may write 4 extra bytes beyond the area that should be written
3696 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3697 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3698 if(!dest_conv_addr) {
3699 ERR("Out of memory\n");
3700 /* Continue without storing converted vertices */
3702 dest_conv = dest_conv_addr;
3705 /* Should I clip?
3706 * a) WINED3DRS_CLIPPING is enabled
3707 * b) WINED3DVOP_CLIP is passed
3709 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3710 static BOOL warned = FALSE;
3712 * The clipping code is not quite correct. Some things need
3713 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3714 * so disable clipping for now.
3715 * (The graphics in Half-Life are broken, and my processvertices
3716 * test crashes with IDirect3DDevice3)
3717 doClip = TRUE;
3719 doClip = FALSE;
3720 if(!warned) {
3721 warned = TRUE;
3722 FIXME("Clipping is broken and disabled for now\n");
3724 } else doClip = FALSE;
3725 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3727 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3728 WINED3DTS_VIEW,
3729 &view_mat);
3730 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3731 WINED3DTS_PROJECTION,
3732 &proj_mat);
3733 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3734 WINED3DTS_WORLDMATRIX(0),
3735 &world_mat);
3737 TRACE("View mat:\n");
3738 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);
3739 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);
3740 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);
3741 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);
3743 TRACE("Proj mat:\n");
3744 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);
3745 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);
3746 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);
3747 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);
3749 TRACE("World mat:\n");
3750 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);
3751 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);
3752 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);
3753 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);
3755 /* Get the viewport */
3756 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3757 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3758 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3760 multiply_matrix(&mat,&view_mat,&world_mat);
3761 multiply_matrix(&mat,&proj_mat,&mat);
3763 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3765 for (i = 0; i < dwCount; i+= 1) {
3766 unsigned int tex_index;
3768 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3769 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3770 /* The position first */
3771 float *p =
3772 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3773 float x, y, z, rhw;
3774 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3776 /* Multiplication with world, view and projection matrix */
3777 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);
3778 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);
3779 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);
3780 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);
3782 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3784 /* WARNING: The following things are taken from d3d7 and were not yet checked
3785 * against d3d8 or d3d9!
3788 /* Clipping conditions: From
3789 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3791 * A vertex is clipped if it does not match the following requirements
3792 * -rhw < x <= rhw
3793 * -rhw < y <= rhw
3794 * 0 < z <= rhw
3795 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3797 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3798 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3802 if( !doClip ||
3803 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3804 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3805 ( rhw > eps ) ) ) {
3807 /* "Normal" viewport transformation (not clipped)
3808 * 1) The values are divided by rhw
3809 * 2) The y axis is negative, so multiply it with -1
3810 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3811 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3812 * 4) Multiply x with Width/2 and add Width/2
3813 * 5) The same for the height
3814 * 6) Add the viewpoint X and Y to the 2D coordinates and
3815 * The minimum Z value to z
3816 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3818 * Well, basically it's simply a linear transformation into viewport
3819 * coordinates
3822 x /= rhw;
3823 y /= rhw;
3824 z /= rhw;
3826 y *= -1;
3828 x *= vp.Width / 2;
3829 y *= vp.Height / 2;
3830 z *= vp.MaxZ - vp.MinZ;
3832 x += vp.Width / 2 + vp.X;
3833 y += vp.Height / 2 + vp.Y;
3834 z += vp.MinZ;
3836 rhw = 1 / rhw;
3837 } else {
3838 /* That vertex got clipped
3839 * Contrary to OpenGL it is not dropped completely, it just
3840 * undergoes a different calculation.
3842 TRACE("Vertex got clipped\n");
3843 x += rhw;
3844 y += rhw;
3846 x /= 2;
3847 y /= 2;
3849 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3850 * outside of the main vertex buffer memory. That needs some more
3851 * investigation...
3855 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3858 ( (float *) dest_ptr)[0] = x;
3859 ( (float *) dest_ptr)[1] = y;
3860 ( (float *) dest_ptr)[2] = z;
3861 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3863 dest_ptr += 3 * sizeof(float);
3865 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3866 dest_ptr += sizeof(float);
3869 if(dest_conv) {
3870 float w = 1 / rhw;
3871 ( (float *) dest_conv)[0] = x * w;
3872 ( (float *) dest_conv)[1] = y * w;
3873 ( (float *) dest_conv)[2] = z * w;
3874 ( (float *) dest_conv)[3] = w;
3876 dest_conv += 3 * sizeof(float);
3878 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3879 dest_conv += sizeof(float);
3883 if (DestFVF & WINED3DFVF_PSIZE) {
3884 dest_ptr += sizeof(DWORD);
3885 if(dest_conv) dest_conv += sizeof(DWORD);
3887 if (DestFVF & WINED3DFVF_NORMAL) {
3888 float *normal =
3889 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3890 /* AFAIK this should go into the lighting information */
3891 FIXME("Didn't expect the destination to have a normal\n");
3892 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3893 if(dest_conv) {
3894 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3898 if (DestFVF & WINED3DFVF_DIFFUSE) {
3899 DWORD *color_d =
3900 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3901 if(!color_d) {
3902 static BOOL warned = FALSE;
3904 if(!warned) {
3905 ERR("No diffuse color in source, but destination has one\n");
3906 warned = TRUE;
3909 *( (DWORD *) dest_ptr) = 0xffffffff;
3910 dest_ptr += sizeof(DWORD);
3912 if(dest_conv) {
3913 *( (DWORD *) dest_conv) = 0xffffffff;
3914 dest_conv += sizeof(DWORD);
3917 else {
3918 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3919 if(dest_conv) {
3920 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3921 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3922 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3923 dest_conv += sizeof(DWORD);
3928 if (DestFVF & WINED3DFVF_SPECULAR) {
3929 /* What's the color value in the feedback buffer? */
3930 DWORD *color_s =
3931 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3932 if(!color_s) {
3933 static BOOL warned = FALSE;
3935 if(!warned) {
3936 ERR("No specular color in source, but destination has one\n");
3937 warned = TRUE;
3940 *( (DWORD *) dest_ptr) = 0xFF000000;
3941 dest_ptr += sizeof(DWORD);
3943 if(dest_conv) {
3944 *( (DWORD *) dest_conv) = 0xFF000000;
3945 dest_conv += sizeof(DWORD);
3948 else {
3949 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3950 if(dest_conv) {
3951 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3952 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3953 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3954 dest_conv += sizeof(DWORD);
3959 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3960 float *tex_coord =
3961 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3962 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3963 if(!tex_coord) {
3964 ERR("No source texture, but destination requests one\n");
3965 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3966 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3968 else {
3969 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3970 if(dest_conv) {
3971 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3977 if(dest_conv) {
3978 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3979 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3980 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3981 dwCount * get_flexible_vertex_size(DestFVF),
3982 dest_conv_addr));
3983 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3984 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3987 LEAVE_GL();
3989 return WINED3D_OK;
3991 #undef copy_and_next
3993 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3995 WineDirect3DVertexStridedData strided;
3996 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3997 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3999 if(pVertexDecl) {
4000 ERR("Output vertex declaration not implemented yet\n");
4003 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4004 * and this call is quite performance critical, so don't call needlessly
4006 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4007 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4010 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4011 * control the streamIsUP flag, thus restore it afterwards.
4013 This->stateBlock->streamIsUP = FALSE;
4014 memset(&strided, 0, sizeof(strided));
4015 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4016 This->stateBlock->streamIsUP = streamWasUP;
4018 if(vbo || SrcStartIndex) {
4019 unsigned int i;
4020 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4021 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4023 * Also get the start index in, but only loop over all elements if there's something to add at all.
4025 #define FIXSRC(type) \
4026 if(strided.u.s.type.VBO) { \
4027 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4028 strided.u.s.type.VBO = 0; \
4029 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4030 ENTER_GL(); \
4031 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4032 vb->vbo = 0; \
4033 LEAVE_GL(); \
4035 if(strided.u.s.type.lpData) { \
4036 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4038 FIXSRC(position);
4039 FIXSRC(blendWeights);
4040 FIXSRC(blendMatrixIndices);
4041 FIXSRC(normal);
4042 FIXSRC(pSize);
4043 FIXSRC(diffuse);
4044 FIXSRC(specular);
4045 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4046 FIXSRC(texCoords[i]);
4048 FIXSRC(position2);
4049 FIXSRC(normal2);
4050 FIXSRC(tangent);
4051 FIXSRC(binormal);
4052 FIXSRC(tessFactor);
4053 FIXSRC(fog);
4054 FIXSRC(depth);
4055 FIXSRC(sample);
4056 #undef FIXSRC
4059 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4062 /*****
4063 * Get / Set Texture Stage States
4064 * TODO: Verify against dx9 definitions
4065 *****/
4066 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4068 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4070 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4072 if (Stage >= MAX_TEXTURES) {
4073 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4074 return WINED3D_OK;
4077 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4078 This->updateStateBlock->textureState[Stage][Type] = Value;
4080 if (This->isRecordingState) {
4081 TRACE("Recording... not performing anything\n");
4082 return WINED3D_OK;
4085 /* Checked after the assignments to allow proper stateblock recording */
4086 if(oldValue == Value) {
4087 TRACE("App is setting the old value over, nothing to do\n");
4088 return WINED3D_OK;
4091 if(Stage > This->stateBlock->lowest_disabled_stage &&
4092 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4093 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4094 * Changes in other states are important on disabled stages too
4096 return WINED3D_OK;
4099 if(Type == WINED3DTSS_COLOROP) {
4100 int i;
4102 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4103 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4104 * they have to be disabled
4106 * The current stage is dirtified below.
4108 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4109 TRACE("Additionally dirtifying stage %d\n", i);
4110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4112 This->stateBlock->lowest_disabled_stage = Stage;
4113 TRACE("New lowest disabled: %d\n", Stage);
4114 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4115 /* Previously disabled stage enabled. Stages above it may need enabling
4116 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4117 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4119 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4122 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4123 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4124 break;
4126 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4127 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4129 This->stateBlock->lowest_disabled_stage = i;
4130 TRACE("New lowest disabled: %d\n", i);
4132 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4133 /* TODO: Built a stage -> texture unit mapping for register combiners */
4137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4139 return WINED3D_OK;
4142 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4144 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4145 *pValue = This->updateStateBlock->textureState[Stage][Type];
4146 return WINED3D_OK;
4149 /*****
4150 * Get / Set Texture
4151 *****/
4152 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4154 IWineD3DBaseTexture *oldTexture;
4156 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4158 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4159 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4162 oldTexture = This->updateStateBlock->textures[Stage];
4164 if(pTexture != NULL) {
4165 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4167 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4168 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4169 return WINED3DERR_INVALIDCALL;
4171 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4174 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4175 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4177 This->updateStateBlock->changed.textures[Stage] = TRUE;
4178 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4179 This->updateStateBlock->textures[Stage] = pTexture;
4181 /* Handle recording of state blocks */
4182 if (This->isRecordingState) {
4183 TRACE("Recording... not performing anything\n");
4184 return WINED3D_OK;
4187 if(oldTexture == pTexture) {
4188 TRACE("App is setting the same texture again, nothing to do\n");
4189 return WINED3D_OK;
4192 /** NOTE: MSDN says that setTexture increases the reference count,
4193 * and the the application must set the texture back to null (or have a leaky application),
4194 * This means we should pass the refcount up to the parent
4195 *******************************/
4196 if (NULL != This->updateStateBlock->textures[Stage]) {
4197 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4198 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4200 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4201 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4202 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4203 * so the COLOROP and ALPHAOP have to be dirtified.
4205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4208 if(bindCount == 1) {
4209 new->baseTexture.sampler = Stage;
4211 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4215 if (NULL != oldTexture) {
4216 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4217 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4219 IWineD3DBaseTexture_Release(oldTexture);
4220 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4225 if(bindCount && old->baseTexture.sampler == Stage) {
4226 int i;
4227 /* Have to do a search for the other sampler(s) where the texture is bound to
4228 * Shouldn't happen as long as apps bind a texture only to one stage
4230 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4231 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4232 if(This->updateStateBlock->textures[i] == oldTexture) {
4233 old->baseTexture.sampler = i;
4234 break;
4240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4242 return WINED3D_OK;
4245 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4248 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4250 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4251 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4254 *ppTexture=This->stateBlock->textures[Stage];
4255 if (*ppTexture)
4256 IWineD3DBaseTexture_AddRef(*ppTexture);
4258 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4260 return WINED3D_OK;
4263 /*****
4264 * Get Back Buffer
4265 *****/
4266 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4267 IWineD3DSurface **ppBackBuffer) {
4268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4269 IWineD3DSwapChain *swapChain;
4270 HRESULT hr;
4272 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4274 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4275 if (hr == WINED3D_OK) {
4276 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4277 IWineD3DSwapChain_Release(swapChain);
4278 } else {
4279 *ppBackBuffer = NULL;
4281 return hr;
4284 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 WARN("(%p) : stub, calling idirect3d for now\n", This);
4287 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4290 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4292 IWineD3DSwapChain *swapChain;
4293 HRESULT hr;
4295 if(iSwapChain > 0) {
4296 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4297 if (hr == WINED3D_OK) {
4298 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4299 IWineD3DSwapChain_Release(swapChain);
4300 } else {
4301 FIXME("(%p) Error getting display mode\n", This);
4303 } else {
4304 /* Don't read the real display mode,
4305 but return the stored mode instead. X11 can't change the color
4306 depth, and some apps are pretty angry if they SetDisplayMode from
4307 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4309 Also don't relay to the swapchain because with ddraw it's possible
4310 that there isn't a swapchain at all */
4311 pMode->Width = This->ddraw_width;
4312 pMode->Height = This->ddraw_height;
4313 pMode->Format = This->ddraw_format;
4314 pMode->RefreshRate = 0;
4315 hr = WINED3D_OK;
4318 return hr;
4321 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4323 TRACE("(%p)->(%p)\n", This, hWnd);
4325 if(This->ddraw_fullscreen) {
4326 if(This->ddraw_window && This->ddraw_window != hWnd) {
4327 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4329 if(hWnd && This->ddraw_window != hWnd) {
4330 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4334 This->ddraw_window = hWnd;
4335 return WINED3D_OK;
4338 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4340 TRACE("(%p)->(%p)\n", This, hWnd);
4342 *hWnd = This->ddraw_window;
4343 return WINED3D_OK;
4346 /*****
4347 * Stateblock related functions
4348 *****/
4350 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4352 IWineD3DStateBlockImpl *object;
4353 HRESULT temp_result;
4354 int i;
4356 TRACE("(%p)\n", This);
4358 if (This->isRecordingState) {
4359 return WINED3DERR_INVALIDCALL;
4362 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4363 if (NULL == object ) {
4364 FIXME("(%p)Error allocating memory for stateblock\n", This);
4365 return E_OUTOFMEMORY;
4367 TRACE("(%p) created object %p\n", This, object);
4368 object->wineD3DDevice= This;
4369 /** FIXME: object->parent = parent; **/
4370 object->parent = NULL;
4371 object->blockType = WINED3DSBT_RECORDED;
4372 object->ref = 1;
4373 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4375 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4376 list_init(&object->lightMap[i]);
4379 temp_result = allocate_shader_constants(object);
4380 if (WINED3D_OK != temp_result)
4381 return temp_result;
4383 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4384 This->updateStateBlock = object;
4385 This->isRecordingState = TRUE;
4387 TRACE("(%p) recording stateblock %p\n",This , object);
4388 return WINED3D_OK;
4391 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4393 unsigned int i, j;
4394 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4396 if (!This->isRecordingState) {
4397 FIXME("(%p) not recording! returning error\n", This);
4398 *ppStateBlock = NULL;
4399 return WINED3DERR_INVALIDCALL;
4402 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4403 if(object->changed.renderState[i]) {
4404 object->contained_render_states[object->num_contained_render_states] = i;
4405 object->num_contained_render_states++;
4408 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4409 if(object->changed.transform[i]) {
4410 object->contained_transform_states[object->num_contained_transform_states] = i;
4411 object->num_contained_transform_states++;
4414 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4415 if(object->changed.vertexShaderConstantsF[i]) {
4416 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4417 object->num_contained_vs_consts_f++;
4420 for(i = 0; i < MAX_CONST_I; i++) {
4421 if(object->changed.vertexShaderConstantsI[i]) {
4422 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4423 object->num_contained_vs_consts_i++;
4426 for(i = 0; i < MAX_CONST_B; i++) {
4427 if(object->changed.vertexShaderConstantsB[i]) {
4428 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4429 object->num_contained_vs_consts_b++;
4432 for(i = 0; i < MAX_CONST_I; i++) {
4433 if(object->changed.pixelShaderConstantsI[i]) {
4434 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4435 object->num_contained_ps_consts_i++;
4438 for(i = 0; i < MAX_CONST_B; i++) {
4439 if(object->changed.pixelShaderConstantsB[i]) {
4440 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4441 object->num_contained_ps_consts_b++;
4444 for(i = 0; i < MAX_TEXTURES; i++) {
4445 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4446 if(object->changed.textureState[i][j]) {
4447 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4448 object->contained_tss_states[object->num_contained_tss_states].state = j;
4449 object->num_contained_tss_states++;
4453 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4454 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4455 if(object->changed.samplerState[i][j]) {
4456 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4457 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4458 object->num_contained_sampler_states++;
4463 *ppStateBlock = (IWineD3DStateBlock*) object;
4464 This->isRecordingState = FALSE;
4465 This->updateStateBlock = This->stateBlock;
4466 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4467 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4468 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4469 return WINED3D_OK;
4472 /*****
4473 * Scene related functions
4474 *****/
4475 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4476 /* At the moment we have no need for any functionality at the beginning
4477 of a scene */
4478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4479 TRACE("(%p)\n", This);
4481 if(This->inScene) {
4482 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4483 return WINED3DERR_INVALIDCALL;
4485 This->inScene = TRUE;
4486 return WINED3D_OK;
4489 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4491 TRACE("(%p)\n", This);
4493 if(!This->inScene) {
4494 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4495 return WINED3DERR_INVALIDCALL;
4498 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4499 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4501 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4502 ENTER_GL();
4503 glFlush();
4504 checkGLcall("glFlush");
4505 LEAVE_GL();
4507 This->inScene = FALSE;
4508 return WINED3D_OK;
4511 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4512 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4513 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 IWineD3DSwapChain *swapChain = NULL;
4516 int i;
4517 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4519 TRACE("(%p) Presenting the frame\n", This);
4521 for(i = 0 ; i < swapchains ; i ++) {
4523 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4524 TRACE("presentinng chain %d, %p\n", i, swapChain);
4525 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4526 IWineD3DSwapChain_Release(swapChain);
4529 return WINED3D_OK;
4532 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4533 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4535 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4537 GLbitfield glMask = 0;
4538 unsigned int i;
4539 CONST WINED3DRECT* curRect;
4541 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4542 Count, pRects, Flags, Color, Z, Stencil);
4544 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4545 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4546 /* TODO: What about depth stencil buffers without stencil bits? */
4547 return WINED3DERR_INVALIDCALL;
4550 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4551 * and not the last active one.
4553 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4554 ENTER_GL();
4556 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4557 apply_fbo_state(iface);
4560 if (Count > 0 && pRects) {
4561 curRect = pRects;
4562 } else {
4563 curRect = NULL;
4566 /* Only set the values up once, as they are not changing */
4567 if (Flags & WINED3DCLEAR_STENCIL) {
4568 glClearStencil(Stencil);
4569 checkGLcall("glClearStencil");
4570 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4571 glStencilMask(0xFFFFFFFF);
4574 if (Flags & WINED3DCLEAR_ZBUFFER) {
4575 glDepthMask(GL_TRUE);
4576 glClearDepth(Z);
4577 checkGLcall("glClearDepth");
4578 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4582 if (Flags & WINED3DCLEAR_TARGET) {
4583 TRACE("Clearing screen with glClear to color %x\n", Color);
4584 glClearColor(D3DCOLOR_R(Color),
4585 D3DCOLOR_G(Color),
4586 D3DCOLOR_B(Color),
4587 D3DCOLOR_A(Color));
4588 checkGLcall("glClearColor");
4590 /* Clear ALL colors! */
4591 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4592 glMask = glMask | GL_COLOR_BUFFER_BIT;
4595 if (!curRect) {
4596 /* In drawable flag is set below */
4598 if (This->render_offscreen) {
4599 glScissor(This->stateBlock->viewport.X,
4600 This->stateBlock->viewport.Y,
4601 This->stateBlock->viewport.Width,
4602 This->stateBlock->viewport.Height);
4603 } else {
4604 glScissor(This->stateBlock->viewport.X,
4605 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4606 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4607 This->stateBlock->viewport.Width,
4608 This->stateBlock->viewport.Height);
4610 checkGLcall("glScissor");
4611 glClear(glMask);
4612 checkGLcall("glClear");
4613 } else {
4614 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4615 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4617 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4618 curRect[0].x2 < target->currentDesc.Width ||
4619 curRect[0].y2 < target->currentDesc.Height) {
4620 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4621 blt_to_drawable(This, target);
4625 /* Now process each rect in turn */
4626 for (i = 0; i < Count; i++) {
4627 /* Note gl uses lower left, width/height */
4628 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4629 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4630 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4631 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4633 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4634 * The rectangle is not cleared, no error is returned, but further rectanlges are
4635 * still cleared if they are valid
4637 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4638 TRACE("Rectangle with negative dimensions, ignoring\n");
4639 continue;
4642 if(This->render_offscreen) {
4643 glScissor(curRect[i].x1, curRect[i].y1,
4644 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4645 } else {
4646 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4647 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4649 checkGLcall("glScissor");
4651 glClear(glMask);
4652 checkGLcall("glClear");
4656 /* Restore the old values (why..?) */
4657 if (Flags & WINED3DCLEAR_STENCIL) {
4658 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4660 if (Flags & WINED3DCLEAR_TARGET) {
4661 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4662 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4663 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4664 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4665 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4668 LEAVE_GL();
4670 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4671 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4673 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4674 target->Flags |= SFLAG_INTEXTURE;
4675 target->Flags &= ~SFLAG_INSYSMEM;
4676 } else {
4677 target->Flags |= SFLAG_INDRAWABLE;
4678 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4680 return WINED3D_OK;
4683 /*****
4684 * Drawing functions
4685 *****/
4686 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4687 UINT PrimitiveCount) {
4689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4692 debug_d3dprimitivetype(PrimitiveType),
4693 StartVertex, PrimitiveCount);
4695 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4696 if(This->stateBlock->streamIsUP) {
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4698 This->stateBlock->streamIsUP = FALSE;
4701 if(This->stateBlock->loadBaseVertexIndex != 0) {
4702 This->stateBlock->loadBaseVertexIndex = 0;
4703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4705 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4706 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4707 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4708 return WINED3D_OK;
4711 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4712 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4713 WINED3DPRIMITIVETYPE PrimitiveType,
4714 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4717 UINT idxStride = 2;
4718 IWineD3DIndexBuffer *pIB;
4719 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4720 GLuint vbo;
4722 pIB = This->stateBlock->pIndexData;
4723 if (!pIB) {
4724 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4725 * without an index buffer set. (The first time at least...)
4726 * D3D8 simply dies, but I doubt it can do much harm to return
4727 * D3DERR_INVALIDCALL there as well. */
4728 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4729 return WINED3DERR_INVALIDCALL;
4732 if(This->stateBlock->streamIsUP) {
4733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4734 This->stateBlock->streamIsUP = FALSE;
4736 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4738 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4739 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4740 minIndex, NumVertices, startIndex, primCount);
4742 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4743 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4744 idxStride = 2;
4745 } else {
4746 idxStride = 4;
4749 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4750 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4754 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4755 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4757 return WINED3D_OK;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4761 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4762 UINT VertexStreamZeroStride) {
4763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4764 IWineD3DVertexBuffer *vb;
4766 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4767 debug_d3dprimitivetype(PrimitiveType),
4768 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4770 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4771 vb = This->stateBlock->streamSource[0];
4772 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4773 if(vb) IWineD3DVertexBuffer_Release(vb);
4774 This->stateBlock->streamOffset[0] = 0;
4775 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4776 This->stateBlock->streamIsUP = TRUE;
4777 This->stateBlock->loadBaseVertexIndex = 0;
4779 /* TODO: Only mark dirty if drawing from a different UP address */
4780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4782 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4783 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4785 /* MSDN specifies stream zero settings must be set to NULL */
4786 This->stateBlock->streamStride[0] = 0;
4787 This->stateBlock->streamSource[0] = NULL;
4789 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4790 * the new stream sources or use UP drawing again
4792 return WINED3D_OK;
4795 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4796 UINT MinVertexIndex, UINT NumVertices,
4797 UINT PrimitiveCount, CONST void* pIndexData,
4798 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4799 UINT VertexStreamZeroStride) {
4800 int idxStride;
4801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4802 IWineD3DVertexBuffer *vb;
4803 IWineD3DIndexBuffer *ib;
4805 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4806 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4807 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4808 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4810 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4811 idxStride = 2;
4812 } else {
4813 idxStride = 4;
4816 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4817 vb = This->stateBlock->streamSource[0];
4818 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4819 if(vb) IWineD3DVertexBuffer_Release(vb);
4820 This->stateBlock->streamIsUP = TRUE;
4821 This->stateBlock->streamOffset[0] = 0;
4822 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4824 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4825 This->stateBlock->baseVertexIndex = 0;
4826 This->stateBlock->loadBaseVertexIndex = 0;
4827 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4829 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4831 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4833 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4834 This->stateBlock->streamSource[0] = NULL;
4835 This->stateBlock->streamStride[0] = 0;
4836 ib = This->stateBlock->pIndexData;
4837 if(ib) {
4838 IWineD3DIndexBuffer_Release(ib);
4839 This->stateBlock->pIndexData = NULL;
4841 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4842 * SetStreamSource to specify a vertex buffer
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4851 /* Mark the state dirty until we have nicer tracking
4852 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4853 * that value.
4855 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4857 This->stateBlock->baseVertexIndex = 0;
4858 This->up_strided = DrawPrimStrideData;
4859 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4860 This->up_strided = NULL;
4861 return WINED3D_OK;
4864 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4866 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4868 /* Mark the state dirty until we have nicer tracking
4869 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4870 * that value.
4872 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4874 This->stateBlock->streamIsUP = TRUE;
4875 This->stateBlock->baseVertexIndex = 0;
4876 This->up_strided = DrawPrimStrideData;
4877 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4878 This->up_strided = NULL;
4879 return WINED3D_OK;
4883 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4884 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4885 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4886 HRESULT hr = WINED3D_OK;
4887 WINED3DRESOURCETYPE sourceType;
4888 WINED3DRESOURCETYPE destinationType;
4889 int i ,levels;
4891 /* TODO: think about moving the code into IWineD3DBaseTexture */
4893 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4895 /* verify that the source and destination textures aren't NULL */
4896 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4897 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4898 This, pSourceTexture, pDestinationTexture);
4899 hr = WINED3DERR_INVALIDCALL;
4902 if (pSourceTexture == pDestinationTexture) {
4903 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4904 This, pSourceTexture, pDestinationTexture);
4905 hr = WINED3DERR_INVALIDCALL;
4907 /* Verify that the source and destination textures are the same type */
4908 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4909 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4911 if (sourceType != destinationType) {
4912 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4913 This);
4914 hr = WINED3DERR_INVALIDCALL;
4917 /* check that both textures have the identical numbers of levels */
4918 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4919 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4920 hr = WINED3DERR_INVALIDCALL;
4923 if (WINED3D_OK == hr) {
4925 /* Make sure that the destination texture is loaded */
4926 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4928 /* Update every surface level of the texture */
4929 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4931 switch (sourceType) {
4932 case WINED3DRTYPE_TEXTURE:
4934 IWineD3DSurface *srcSurface;
4935 IWineD3DSurface *destSurface;
4937 for (i = 0 ; i < levels ; ++i) {
4938 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4939 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4940 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4941 IWineD3DSurface_Release(srcSurface);
4942 IWineD3DSurface_Release(destSurface);
4943 if (WINED3D_OK != hr) {
4944 WARN("(%p) : Call to update surface failed\n", This);
4945 return hr;
4949 break;
4950 case WINED3DRTYPE_CUBETEXTURE:
4952 IWineD3DSurface *srcSurface;
4953 IWineD3DSurface *destSurface;
4954 WINED3DCUBEMAP_FACES faceType;
4956 for (i = 0 ; i < levels ; ++i) {
4957 /* Update each cube face */
4958 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4959 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4960 if (WINED3D_OK != hr) {
4961 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4962 } else {
4963 TRACE("Got srcSurface %p\n", srcSurface);
4965 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4966 if (WINED3D_OK != hr) {
4967 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4968 } else {
4969 TRACE("Got desrSurface %p\n", destSurface);
4971 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4972 IWineD3DSurface_Release(srcSurface);
4973 IWineD3DSurface_Release(destSurface);
4974 if (WINED3D_OK != hr) {
4975 WARN("(%p) : Call to update surface failed\n", This);
4976 return hr;
4981 break;
4982 #if 0 /* TODO: Add support for volume textures */
4983 case WINED3DRTYPE_VOLUMETEXTURE:
4985 IWineD3DVolume srcVolume = NULL;
4986 IWineD3DSurface destVolume = NULL;
4988 for (i = 0 ; i < levels ; ++i) {
4989 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4990 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4991 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4992 IWineD3DVolume_Release(srcSurface);
4993 IWineD3DVolume_Release(destSurface);
4994 if (WINED3D_OK != hr) {
4995 WARN("(%p) : Call to update volume failed\n", This);
4996 return hr;
5000 break;
5001 #endif
5002 default:
5003 FIXME("(%p) : Unsupported source and destination type\n", This);
5004 hr = WINED3DERR_INVALIDCALL;
5008 return hr;
5011 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5012 IWineD3DSwapChain *swapChain;
5013 HRESULT hr;
5014 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5015 if(hr == WINED3D_OK) {
5016 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5017 IWineD3DSwapChain_Release(swapChain);
5019 return hr;
5022 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5024 /* return a sensible default */
5025 *pNumPasses = 1;
5026 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5027 FIXME("(%p) : stub\n", This);
5028 return WINED3D_OK;
5031 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5032 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5033 int j;
5034 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5035 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5036 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5037 return WINED3DERR_INVALIDCALL;
5039 for (j = 0; j < 256; ++j) {
5040 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5041 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5042 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5043 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5045 TRACE("(%p) : returning\n", This);
5046 return WINED3D_OK;
5049 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5051 int j;
5052 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5053 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5054 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5055 return WINED3DERR_INVALIDCALL;
5057 for (j = 0; j < 256; ++j) {
5058 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5059 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5060 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5061 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5063 TRACE("(%p) : returning\n", This);
5064 return WINED3D_OK;
5067 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5069 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5070 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5071 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5072 return WINED3DERR_INVALIDCALL;
5074 /*TODO: stateblocks */
5075 This->currentPalette = PaletteNumber;
5076 TRACE("(%p) : returning\n", This);
5077 return WINED3D_OK;
5080 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5082 if (PaletteNumber == NULL) {
5083 WARN("(%p) : returning Invalid Call\n", This);
5084 return WINED3DERR_INVALIDCALL;
5086 /*TODO: stateblocks */
5087 *PaletteNumber = This->currentPalette;
5088 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5089 return WINED3D_OK;
5092 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5094 static BOOL showFixmes = TRUE;
5095 if (showFixmes) {
5096 FIXME("(%p) : stub\n", This);
5097 showFixmes = FALSE;
5100 This->softwareVertexProcessing = bSoftware;
5101 return WINED3D_OK;
5105 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5107 static BOOL showFixmes = TRUE;
5108 if (showFixmes) {
5109 FIXME("(%p) : stub\n", This);
5110 showFixmes = FALSE;
5112 return This->softwareVertexProcessing;
5116 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5118 IWineD3DSwapChain *swapChain;
5119 HRESULT hr;
5121 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5123 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5124 if(hr == WINED3D_OK){
5125 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5126 IWineD3DSwapChain_Release(swapChain);
5127 }else{
5128 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5130 return hr;
5134 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 static BOOL showfixmes = TRUE;
5137 if(nSegments != 0.0f) {
5138 if( showfixmes) {
5139 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5140 showfixmes = FALSE;
5143 return WINED3D_OK;
5146 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 static BOOL showfixmes = TRUE;
5149 if( showfixmes) {
5150 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5151 showfixmes = FALSE;
5153 return 0.0f;
5156 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5158 /** TODO: remove casts to IWineD3DSurfaceImpl
5159 * NOTE: move code to surface to accomplish this
5160 ****************************************/
5161 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5162 int srcWidth, srcHeight;
5163 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5164 WINED3DFORMAT destFormat, srcFormat;
5165 UINT destSize;
5166 int srcLeft, destLeft, destTop;
5167 WINED3DPOOL srcPool, destPool;
5168 int offset = 0;
5169 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5170 glDescriptor *glDescription = NULL;
5171 GLenum dummy;
5172 int bpp;
5173 CONVERT_TYPES convert = NO_CONVERSION;
5175 WINED3DSURFACE_DESC winedesc;
5177 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5178 memset(&winedesc, 0, sizeof(winedesc));
5179 winedesc.Width = &srcSurfaceWidth;
5180 winedesc.Height = &srcSurfaceHeight;
5181 winedesc.Pool = &srcPool;
5182 winedesc.Format = &srcFormat;
5184 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5186 winedesc.Width = &destSurfaceWidth;
5187 winedesc.Height = &destSurfaceHeight;
5188 winedesc.Pool = &destPool;
5189 winedesc.Format = &destFormat;
5190 winedesc.Size = &destSize;
5192 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5194 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5195 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5196 return WINED3DERR_INVALIDCALL;
5199 /* This call loads the opengl surface directly, instead of copying the surface to the
5200 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5201 * copy in sysmem and use regular surface loading.
5203 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5204 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5205 if(convert != NO_CONVERSION) {
5206 return IWineD3DSurface_BltFast(pDestinationSurface,
5207 pDestPoint ? pDestPoint->x : 0,
5208 pDestPoint ? pDestPoint->y : 0,
5209 pSourceSurface, (RECT *) pSourceRect, 0);
5212 if (destFormat == WINED3DFMT_UNKNOWN) {
5213 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5214 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5216 /* Get the update surface description */
5217 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5220 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5222 ENTER_GL();
5224 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5225 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5226 checkGLcall("glActiveTextureARB");
5229 /* Make sure the surface is loaded and up to date */
5230 IWineD3DSurface_PreLoad(pDestinationSurface);
5232 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5234 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5235 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5236 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5237 srcLeft = pSourceRect ? pSourceRect->left : 0;
5238 destLeft = pDestPoint ? pDestPoint->x : 0;
5239 destTop = pDestPoint ? pDestPoint->y : 0;
5242 /* This function doesn't support compressed textures
5243 the pitch is just bytesPerPixel * width */
5244 if(srcWidth != srcSurfaceWidth || srcLeft ){
5245 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5246 offset += srcLeft * pSrcSurface->bytesPerPixel;
5247 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5249 /* TODO DXT formats */
5251 if(pSourceRect != NULL && pSourceRect->top != 0){
5252 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5254 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5255 ,This
5256 ,glDescription->level
5257 ,destLeft
5258 ,destTop
5259 ,srcWidth
5260 ,srcHeight
5261 ,glDescription->glFormat
5262 ,glDescription->glType
5263 ,IWineD3DSurface_GetData(pSourceSurface)
5266 /* Sanity check */
5267 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5269 /* need to lock the surface to get the data */
5270 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5273 /* TODO: Cube and volume support */
5274 if(rowoffset != 0){
5275 /* not a whole row so we have to do it a line at a time */
5276 int j;
5278 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5279 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5281 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5283 glTexSubImage2D(glDescription->target
5284 ,glDescription->level
5285 ,destLeft
5287 ,srcWidth
5289 ,glDescription->glFormat
5290 ,glDescription->glType
5291 ,data /* could be quicker using */
5293 data += rowoffset;
5296 } else { /* Full width, so just write out the whole texture */
5298 if (WINED3DFMT_DXT1 == destFormat ||
5299 WINED3DFMT_DXT2 == destFormat ||
5300 WINED3DFMT_DXT3 == destFormat ||
5301 WINED3DFMT_DXT4 == destFormat ||
5302 WINED3DFMT_DXT5 == destFormat) {
5303 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5304 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5305 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5306 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5307 } if (destFormat != srcFormat) {
5308 FIXME("Updating mixed format compressed texture is not curretly support\n");
5309 } else {
5310 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5311 glDescription->level,
5312 glDescription->glFormatInternal,
5313 srcWidth,
5314 srcHeight,
5316 destSize,
5317 IWineD3DSurface_GetData(pSourceSurface));
5319 } else {
5320 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5324 } else {
5325 glTexSubImage2D(glDescription->target
5326 ,glDescription->level
5327 ,destLeft
5328 ,destTop
5329 ,srcWidth
5330 ,srcHeight
5331 ,glDescription->glFormat
5332 ,glDescription->glType
5333 ,IWineD3DSurface_GetData(pSourceSurface)
5337 checkGLcall("glTexSubImage2D");
5339 LEAVE_GL();
5341 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5342 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5343 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5345 return WINED3D_OK;
5348 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 struct WineD3DRectPatch *patch;
5351 unsigned int i;
5352 struct list *e;
5353 BOOL found;
5354 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5356 if(!(Handle || pRectPatchInfo)) {
5357 /* TODO: Write a test for the return value, thus the FIXME */
5358 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5359 return WINED3DERR_INVALIDCALL;
5362 if(Handle) {
5363 i = PATCHMAP_HASHFUNC(Handle);
5364 found = FALSE;
5365 LIST_FOR_EACH(e, &This->patches[i]) {
5366 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5367 if(patch->Handle == Handle) {
5368 found = TRUE;
5369 break;
5373 if(!found) {
5374 TRACE("Patch does not exist. Creating a new one\n");
5375 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5376 patch->Handle = Handle;
5377 list_add_head(&This->patches[i], &patch->entry);
5378 } else {
5379 TRACE("Found existing patch %p\n", patch);
5381 } else {
5382 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5383 * attributes we have to tesselate, read back, and draw. This needs a patch
5384 * management structure instance. Create one.
5386 * A possible improvement is to check if a vertex shader is used, and if not directly
5387 * draw the patch.
5389 FIXME("Drawing an uncached patch. This is slow\n");
5390 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5393 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5394 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5395 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5396 HRESULT hr;
5397 TRACE("Tesselation density or patch info changed, retesselating\n");
5399 if(pRectPatchInfo) {
5400 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5402 patch->numSegs[0] = pNumSegs[0];
5403 patch->numSegs[1] = pNumSegs[1];
5404 patch->numSegs[2] = pNumSegs[2];
5405 patch->numSegs[3] = pNumSegs[3];
5407 hr = tesselate_rectpatch(This, patch);
5408 if(FAILED(hr)) {
5409 WARN("Patch tesselation failed\n");
5411 /* Do not release the handle to store the params of the patch */
5412 if(!Handle) {
5413 HeapFree(GetProcessHeap(), 0, patch);
5415 return hr;
5419 This->currentPatch = patch;
5420 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5421 This->currentPatch = NULL;
5423 /* Destroy uncached patches */
5424 if(!Handle) {
5425 HeapFree(GetProcessHeap(), 0, patch->mem);
5426 HeapFree(GetProcessHeap(), 0, patch);
5428 return WINED3D_OK;
5431 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5432 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5434 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5435 FIXME("(%p) : Stub\n", This);
5436 return WINED3D_OK;
5439 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5441 int i;
5442 struct WineD3DRectPatch *patch;
5443 struct list *e;
5444 TRACE("(%p) Handle(%d)\n", This, Handle);
5446 i = PATCHMAP_HASHFUNC(Handle);
5447 LIST_FOR_EACH(e, &This->patches[i]) {
5448 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5449 if(patch->Handle == Handle) {
5450 TRACE("Deleting patch %p\n", patch);
5451 list_remove(&patch->entry);
5452 HeapFree(GetProcessHeap(), 0, patch->mem);
5453 HeapFree(GetProcessHeap(), 0, patch);
5454 return WINED3D_OK;
5458 /* TODO: Write a test for the return value */
5459 FIXME("Attempt to destroy nonexistant patch\n");
5460 return WINED3DERR_INVALIDCALL;
5463 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5464 HRESULT hr;
5465 IWineD3DSwapChain *swapchain;
5467 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5468 if (SUCCEEDED(hr)) {
5469 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5470 return swapchain;
5473 return NULL;
5476 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5479 if (!*fbo) {
5480 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5481 checkGLcall("glGenFramebuffersEXT()");
5483 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5484 checkGLcall("glBindFramebuffer()");
5487 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5488 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5489 IWineD3DBaseTextureImpl *texture_impl;
5490 GLenum texttarget, target;
5491 GLint old_binding;
5493 texttarget = surface_impl->glDescription.target;
5494 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5495 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5497 IWineD3DSurface_PreLoad(surface);
5499 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5500 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5501 glBindTexture(target, old_binding);
5503 /* Update base texture states array */
5504 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5505 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5506 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5507 if (texture_impl->baseTexture.bindCount) {
5508 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5511 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5514 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5515 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5517 checkGLcall("attach_surface_fbo");
5520 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5522 IWineD3DSwapChain *swapchain;
5524 swapchain = get_swapchain(surface);
5525 if (swapchain) {
5526 GLenum buffer;
5528 TRACE("Surface %p is onscreen\n", surface);
5530 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5531 buffer = surface_get_gl_buffer(surface, swapchain);
5532 glDrawBuffer(buffer);
5533 checkGLcall("glDrawBuffer()");
5534 } else {
5535 TRACE("Surface %p is offscreen\n", surface);
5536 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5537 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5540 if (rect) {
5541 glEnable(GL_SCISSOR_TEST);
5542 if(!swapchain) {
5543 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5544 } else {
5545 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5546 rect->x2 - rect->x1, rect->y2 - rect->y1);
5548 checkGLcall("glScissor");
5549 } else {
5550 glDisable(GL_SCISSOR_TEST);
5552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5554 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5557 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5558 glClear(GL_COLOR_BUFFER_BIT);
5559 checkGLcall("glClear");
5561 if (This->render_offscreen) {
5562 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5563 } else {
5564 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5565 checkGLcall("glBindFramebuffer()");
5568 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5569 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5570 glDrawBuffer(GL_BACK);
5571 checkGLcall("glDrawBuffer()");
5575 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5577 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5578 WINEDDBLTFX BltFx;
5579 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5581 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5582 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5583 return WINED3DERR_INVALIDCALL;
5586 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5587 color_fill_fbo(iface, pSurface, pRect, color);
5588 return WINED3D_OK;
5589 } else {
5590 /* Just forward this to the DirectDraw blitting engine */
5591 memset(&BltFx, 0, sizeof(BltFx));
5592 BltFx.dwSize = sizeof(BltFx);
5593 BltFx.u5.dwFillColor = color;
5594 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5598 /* rendertarget and deptth stencil functions */
5599 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5602 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5603 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5604 return WINED3DERR_INVALIDCALL;
5607 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5608 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5609 /* Note inc ref on returned surface */
5610 if(*ppRenderTarget != NULL)
5611 IWineD3DSurface_AddRef(*ppRenderTarget);
5612 return WINED3D_OK;
5615 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5617 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5618 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5619 IWineD3DSwapChainImpl *Swapchain;
5620 HRESULT hr;
5622 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5624 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5625 if(hr != WINED3D_OK) {
5626 ERR("Can't get the swapchain\n");
5627 return hr;
5630 /* Make sure to release the swapchain */
5631 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5633 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5634 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5635 return WINED3DERR_INVALIDCALL;
5637 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5638 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5639 return WINED3DERR_INVALIDCALL;
5642 if(Swapchain->frontBuffer != Front) {
5643 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5645 if(Swapchain->frontBuffer)
5646 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5647 Swapchain->frontBuffer = Front;
5649 if(Swapchain->frontBuffer) {
5650 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5654 if(Back && !Swapchain->backBuffer) {
5655 /* We need memory for the back buffer array - only one back buffer this way */
5656 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5657 if(!Swapchain->backBuffer) {
5658 ERR("Out of memory\n");
5659 return E_OUTOFMEMORY;
5663 if(Swapchain->backBuffer[0] != Back) {
5664 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5666 /* What to do about the context here in the case of multithreading? Not sure.
5667 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5669 ENTER_GL();
5670 if(!Swapchain->backBuffer[0]) {
5671 /* GL was told to draw to the front buffer at creation,
5672 * undo that
5674 glDrawBuffer(GL_BACK);
5675 checkGLcall("glDrawBuffer(GL_BACK)");
5676 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5677 Swapchain->presentParms.BackBufferCount = 1;
5678 } else if (!Back) {
5679 /* That makes problems - disable for now */
5680 /* glDrawBuffer(GL_FRONT); */
5681 checkGLcall("glDrawBuffer(GL_FRONT)");
5682 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5683 Swapchain->presentParms.BackBufferCount = 0;
5685 LEAVE_GL();
5687 if(Swapchain->backBuffer[0])
5688 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5689 Swapchain->backBuffer[0] = Back;
5691 if(Swapchain->backBuffer[0]) {
5692 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5693 } else {
5694 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5699 return WINED3D_OK;
5702 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 *ppZStencilSurface = This->depthStencilBuffer;
5705 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5707 if(*ppZStencilSurface != NULL) {
5708 /* Note inc ref on returned surface */
5709 IWineD3DSurface_AddRef(*ppZStencilSurface);
5711 return WINED3D_OK;
5714 /* TODO: Handle stencil attachments */
5715 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5717 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5719 TRACE("Set depth stencil to %p\n", depth_stencil);
5721 if (depth_stencil_impl) {
5722 if (depth_stencil_impl->current_renderbuffer) {
5723 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5724 checkGLcall("glFramebufferRenderbufferEXT()");
5725 } else {
5726 IWineD3DBaseTextureImpl *texture_impl;
5727 GLenum texttarget, target;
5728 GLint old_binding = 0;
5730 texttarget = depth_stencil_impl->glDescription.target;
5731 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5732 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5734 IWineD3DSurface_PreLoad(depth_stencil);
5736 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5737 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5738 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5739 glBindTexture(target, old_binding);
5741 /* Update base texture states array */
5742 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5743 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5744 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5745 if (texture_impl->baseTexture.bindCount) {
5746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5749 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5752 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5753 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5754 checkGLcall("glFramebufferTexture2DEXT()");
5756 } else {
5757 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5758 checkGLcall("glFramebufferTexture2DEXT()");
5762 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5766 TRACE("Set render target %u to %p\n", idx, render_target);
5768 if (rtimpl) {
5769 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5770 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5771 } else {
5772 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5773 checkGLcall("glFramebufferTexture2DEXT()");
5775 This->draw_buffers[idx] = GL_NONE;
5779 static void check_fbo_status(IWineD3DDevice *iface) {
5780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5781 GLenum status;
5783 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5784 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5785 TRACE("FBO complete\n");
5786 } else {
5787 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5789 /* Dump the FBO attachments */
5790 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5791 IWineD3DSurfaceImpl *attachment;
5792 int i;
5794 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5795 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5796 if (attachment) {
5797 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5798 attachment->pow2Width, attachment->pow2Height);
5801 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5802 if (attachment) {
5803 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5804 attachment->pow2Width, attachment->pow2Height);
5810 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5812 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5813 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5815 if (!ds_impl) return FALSE;
5817 if (ds_impl->current_renderbuffer) {
5818 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5819 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5822 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5823 rt_impl->pow2Height != ds_impl->pow2Height);
5826 void apply_fbo_state(IWineD3DDevice *iface) {
5827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5828 unsigned int i;
5830 if (This->render_offscreen) {
5831 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5833 /* Apply render targets */
5834 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5835 IWineD3DSurface *render_target = This->render_targets[i];
5836 if (This->fbo_color_attachments[i] != render_target) {
5837 set_render_target_fbo(iface, i, render_target);
5838 This->fbo_color_attachments[i] = render_target;
5842 /* Apply depth targets */
5843 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5844 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5845 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5847 if (This->stencilBufferTarget) {
5848 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5850 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5851 This->fbo_depth_attachment = This->stencilBufferTarget;
5854 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5855 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5856 checkGLcall("glDrawBuffers()");
5857 } else {
5858 glDrawBuffer(This->draw_buffers[0]);
5859 checkGLcall("glDrawBuffer()");
5861 } else {
5862 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5865 check_fbo_status(iface);
5868 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5869 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5871 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5872 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5873 GLenum gl_filter;
5875 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5876 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5877 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5878 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5880 switch (filter) {
5881 case WINED3DTEXF_LINEAR:
5882 gl_filter = GL_LINEAR;
5883 break;
5885 default:
5886 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5887 case WINED3DTEXF_NONE:
5888 case WINED3DTEXF_POINT:
5889 gl_filter = GL_NEAREST;
5890 break;
5893 /* Attach src surface to src fbo */
5894 src_swapchain = get_swapchain(src_surface);
5895 if (src_swapchain) {
5896 GLenum buffer;
5898 TRACE("Source surface %p is onscreen\n", src_surface);
5899 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5901 ENTER_GL();
5902 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5903 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5904 glReadBuffer(buffer);
5905 checkGLcall("glReadBuffer()");
5907 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5908 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5909 } else {
5910 TRACE("Source surface %p is offscreen\n", src_surface);
5911 ENTER_GL();
5912 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5913 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5914 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5915 checkGLcall("glReadBuffer()");
5917 LEAVE_GL();
5919 /* Attach dst surface to dst fbo */
5920 dst_swapchain = get_swapchain(dst_surface);
5921 if (dst_swapchain) {
5922 GLenum buffer;
5924 TRACE("Destination surface %p is onscreen\n", dst_surface);
5925 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5927 ENTER_GL();
5928 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5929 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5930 glDrawBuffer(buffer);
5931 checkGLcall("glDrawBuffer()");
5933 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5934 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5935 } else {
5936 TRACE("Destination surface %p is offscreen\n", dst_surface);
5938 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5939 if(!src_swapchain) {
5940 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5943 ENTER_GL();
5944 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5945 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5946 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5947 checkGLcall("glDrawBuffer()");
5949 glDisable(GL_SCISSOR_TEST);
5950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5952 if (flip) {
5953 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5954 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5955 checkGLcall("glBlitFramebuffer()");
5956 } else {
5957 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5958 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5959 checkGLcall("glBlitFramebuffer()");
5962 if (This->render_offscreen) {
5963 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5964 } else {
5965 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5966 checkGLcall("glBindFramebuffer()");
5969 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5970 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5971 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5972 glDrawBuffer(GL_BACK);
5973 checkGLcall("glDrawBuffer()");
5975 LEAVE_GL();
5978 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5980 WINED3DVIEWPORT viewport;
5982 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5984 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5985 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5986 return WINED3DERR_INVALIDCALL;
5989 /* MSDN says that null disables the render target
5990 but a device must always be associated with a render target
5991 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5993 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5994 for more details
5996 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5997 FIXME("Trying to set render target 0 to NULL\n");
5998 return WINED3DERR_INVALIDCALL;
6000 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6001 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);
6002 return WINED3DERR_INVALIDCALL;
6005 /* If we are trying to set what we already have, don't bother */
6006 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6007 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6008 return WINED3D_OK;
6010 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6011 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6012 This->render_targets[RenderTargetIndex] = pRenderTarget;
6014 /* Render target 0 is special */
6015 if(RenderTargetIndex == 0) {
6016 /* Finally, reset the viewport as the MSDN states. */
6017 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6018 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6019 viewport.X = 0;
6020 viewport.Y = 0;
6021 viewport.MaxZ = 1.0f;
6022 viewport.MinZ = 0.0f;
6023 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6024 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6025 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6029 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6030 * ctx properly.
6031 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6032 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6034 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6036 return WINED3D_OK;
6039 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6041 HRESULT hr = WINED3D_OK;
6042 IWineD3DSurface *tmp;
6044 TRACE("(%p) Swapping z-buffer\n",This);
6046 if (pNewZStencil == This->stencilBufferTarget) {
6047 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6048 } else {
6049 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6050 * depending on the renter target implementation being used.
6051 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6052 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6053 * stencil buffer and incure an extra memory overhead
6054 ******************************************************/
6056 tmp = This->stencilBufferTarget;
6057 This->stencilBufferTarget = pNewZStencil;
6058 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6059 /* should we be calling the parent or the wined3d surface? */
6060 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6061 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6062 hr = WINED3D_OK;
6064 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6065 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6067 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6072 return hr;
6075 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6076 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6078 /* TODO: the use of Impl is deprecated. */
6079 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6080 WINED3DLOCKED_RECT lockedRect;
6082 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6084 /* some basic validation checks */
6085 if(This->cursorTexture) {
6086 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6087 ENTER_GL();
6088 glDeleteTextures(1, &This->cursorTexture);
6089 LEAVE_GL();
6090 This->cursorTexture = 0;
6093 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6094 This->haveHardwareCursor = TRUE;
6095 else
6096 This->haveHardwareCursor = FALSE;
6098 if(pCursorBitmap) {
6099 WINED3DLOCKED_RECT rect;
6101 /* MSDN: Cursor must be A8R8G8B8 */
6102 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6103 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6104 return WINED3DERR_INVALIDCALL;
6107 /* MSDN: Cursor must be smaller than the display mode */
6108 if(pSur->currentDesc.Width > This->ddraw_width ||
6109 pSur->currentDesc.Height > This->ddraw_height) {
6110 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);
6111 return WINED3DERR_INVALIDCALL;
6114 if (!This->haveHardwareCursor) {
6115 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6117 /* Do not store the surface's pointer because the application may
6118 * release it after setting the cursor image. Windows doesn't
6119 * addref the set surface, so we can't do this either without
6120 * creating circular refcount dependencies. Copy out the gl texture
6121 * instead.
6123 This->cursorWidth = pSur->currentDesc.Width;
6124 This->cursorHeight = pSur->currentDesc.Height;
6125 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6127 const GlPixelFormatDesc *glDesc;
6128 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6129 char *mem, *bits = (char *)rect.pBits;
6130 GLint intfmt = glDesc->glInternal;
6131 GLint format = glDesc->glFormat;
6132 GLint type = glDesc->glType;
6133 INT height = This->cursorHeight;
6134 INT width = This->cursorWidth;
6135 INT bpp = tableEntry->bpp;
6136 INT i;
6138 /* Reformat the texture memory (pitch and width can be
6139 * different) */
6140 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6141 for(i = 0; i < height; i++)
6142 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6143 IWineD3DSurface_UnlockRect(pCursorBitmap);
6144 ENTER_GL();
6146 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6147 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6148 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6151 /* Make sure that a proper texture unit is selected */
6152 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6153 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6154 checkGLcall("glActiveTextureARB");
6156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6157 /* Create a new cursor texture */
6158 glGenTextures(1, &This->cursorTexture);
6159 checkGLcall("glGenTextures");
6160 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6161 checkGLcall("glBindTexture");
6162 /* Copy the bitmap memory into the cursor texture */
6163 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6164 HeapFree(GetProcessHeap(), 0, mem);
6165 checkGLcall("glTexImage2D");
6167 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6168 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6169 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6172 LEAVE_GL();
6174 else
6176 FIXME("A cursor texture was not returned.\n");
6177 This->cursorTexture = 0;
6180 else
6182 /* Draw a hardware cursor */
6183 ICONINFO cursorInfo;
6184 HCURSOR cursor;
6185 /* Create and clear maskBits because it is not needed for
6186 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6187 * chunks. */
6188 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6189 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6190 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6191 WINED3DLOCK_NO_DIRTY_UPDATE |
6192 WINED3DLOCK_READONLY
6194 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6195 pSur->currentDesc.Height);
6197 cursorInfo.fIcon = FALSE;
6198 cursorInfo.xHotspot = XHotSpot;
6199 cursorInfo.yHotspot = YHotSpot;
6200 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6201 pSur->currentDesc.Height, 1,
6202 1, &maskBits);
6203 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6204 pSur->currentDesc.Height, 1,
6205 32, lockedRect.pBits);
6206 IWineD3DSurface_UnlockRect(pCursorBitmap);
6207 /* Create our cursor and clean up. */
6208 cursor = CreateIconIndirect(&cursorInfo);
6209 SetCursor(cursor);
6210 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6211 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6212 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6213 This->hardwareCursor = cursor;
6214 HeapFree(GetProcessHeap(), 0, maskBits);
6218 This->xHotSpot = XHotSpot;
6219 This->yHotSpot = YHotSpot;
6220 return WINED3D_OK;
6223 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6225 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6227 This->xScreenSpace = XScreenSpace;
6228 This->yScreenSpace = YScreenSpace;
6230 return;
6234 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6236 BOOL oldVisible = This->bCursorVisible;
6237 POINT pt;
6239 TRACE("(%p) : visible(%d)\n", This, bShow);
6242 * When ShowCursor is first called it should make the cursor appear at the OS's last
6243 * known cursor position. Because of this, some applications just repetitively call
6244 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6246 GetCursorPos(&pt);
6247 This->xScreenSpace = pt.x;
6248 This->yScreenSpace = pt.y;
6250 if (This->haveHardwareCursor) {
6251 This->bCursorVisible = bShow;
6252 if (bShow)
6253 SetCursor(This->hardwareCursor);
6254 else
6255 SetCursor(NULL);
6257 else
6259 if (This->cursorTexture)
6260 This->bCursorVisible = bShow;
6263 return oldVisible;
6266 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6268 TRACE("(%p) : state (%u)\n", This, This->state);
6269 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6270 switch (This->state) {
6271 case WINED3D_OK:
6272 return WINED3D_OK;
6273 case WINED3DERR_DEVICELOST:
6275 ResourceList *resourceList = This->resources;
6276 while (NULL != resourceList) {
6277 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6278 return WINED3DERR_DEVICENOTRESET;
6279 resourceList = resourceList->next;
6281 return WINED3DERR_DEVICELOST;
6283 case WINED3DERR_DRIVERINTERNALERROR:
6284 return WINED3DERR_DRIVERINTERNALERROR;
6287 /* Unknown state */
6288 return WINED3DERR_DRIVERINTERNALERROR;
6292 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6294 /** FIXME: Resource tracking needs to be done,
6295 * The closes we can do to this is set the priorities of all managed textures low
6296 * and then reset them.
6297 ***********************************************************/
6298 FIXME("(%p) : stub\n", This);
6299 return WINED3D_OK;
6302 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6303 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6305 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6306 if(surface->Flags & SFLAG_DIBSECTION) {
6307 /* Release the DC */
6308 SelectObject(surface->hDC, surface->dib.holdbitmap);
6309 DeleteDC(surface->hDC);
6310 /* Release the DIB section */
6311 DeleteObject(surface->dib.DIBsection);
6312 surface->dib.bitmap_data = NULL;
6313 surface->resource.allocatedMemory = NULL;
6314 surface->Flags &= ~SFLAG_DIBSECTION;
6316 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6317 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6318 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6319 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6320 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6321 } else {
6322 surface->pow2Width = surface->pow2Height = 1;
6323 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6324 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6326 if(surface->glDescription.textureName) {
6327 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6328 ENTER_GL();
6329 glDeleteTextures(1, &surface->glDescription.textureName);
6330 LEAVE_GL();
6331 surface->glDescription.textureName = 0;
6332 surface->Flags &= ~SFLAG_CLIENT;
6334 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6335 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6336 surface->Flags |= SFLAG_NONPOW2;
6337 } else {
6338 surface->Flags &= ~SFLAG_NONPOW2;
6340 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6341 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6344 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6346 IWineD3DSwapChainImpl *swapchain;
6347 HRESULT hr;
6348 BOOL DisplayModeChanged = FALSE;
6349 WINED3DDISPLAYMODE mode;
6350 TRACE("(%p)\n", This);
6352 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6353 if(FAILED(hr)) {
6354 ERR("Failed to get the first implicit swapchain\n");
6355 return hr;
6358 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6359 * on an existing gl context, so there's no real need for recreation.
6361 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6363 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6365 TRACE("New params:\n");
6366 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6367 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6368 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6369 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6370 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6371 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6372 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6373 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6374 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6375 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6376 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6377 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6378 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6380 /* No special treatment of these parameters. Just store them */
6381 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6382 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6383 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6384 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6386 /* What to do about these? */
6387 if(pPresentationParameters->BackBufferCount != 0 &&
6388 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6389 ERR("Cannot change the back buffer count yet\n");
6391 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6392 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6393 ERR("Cannot change the back buffer format yet\n");
6395 if(pPresentationParameters->hDeviceWindow != NULL &&
6396 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6397 ERR("Cannot change the device window yet\n");
6399 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6400 ERR("What do do about a changed auto depth stencil parameter?\n");
6403 if(pPresentationParameters->Windowed) {
6404 mode.Width = swapchain->orig_width;
6405 mode.Height = swapchain->orig_height;
6406 mode.RefreshRate = 0;
6407 mode.Format = swapchain->presentParms.BackBufferFormat;
6408 } else {
6409 mode.Width = pPresentationParameters->BackBufferWidth;
6410 mode.Height = pPresentationParameters->BackBufferHeight;
6411 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6412 mode.Format = swapchain->presentParms.BackBufferFormat;
6415 /* Should Width == 800 && Height == 0 set 800x600? */
6416 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6417 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6418 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6420 WINED3DVIEWPORT vp;
6421 int i;
6423 vp.X = 0;
6424 vp.Y = 0;
6425 vp.Width = pPresentationParameters->BackBufferWidth;
6426 vp.Height = pPresentationParameters->BackBufferHeight;
6427 vp.MinZ = 0;
6428 vp.MaxZ = 1;
6430 if(!pPresentationParameters->Windowed) {
6431 DisplayModeChanged = TRUE;
6433 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6434 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6436 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6437 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6438 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6441 /* Now set the new viewport */
6442 IWineD3DDevice_SetViewport(iface, &vp);
6445 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6446 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6447 DisplayModeChanged) {
6449 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6450 if(!pPresentationParameters->Windowed) {
6451 IWineD3DDevice_SetFullscreen(iface, TRUE);
6454 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6456 /* Switching out of fullscreen mode? First set the original res, then change the window */
6457 if(pPresentationParameters->Windowed) {
6458 IWineD3DDevice_SetFullscreen(iface, FALSE);
6460 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6463 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6464 return WINED3D_OK;
6467 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6468 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6469 /** FIXME: always true at the moment **/
6470 if(!bEnableDialogs) {
6471 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6473 return WINED3D_OK;
6477 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6479 TRACE("(%p) : pParameters %p\n", This, pParameters);
6481 *pParameters = This->createParms;
6482 return WINED3D_OK;
6485 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6486 IWineD3DSwapChain *swapchain;
6487 HRESULT hrc = WINED3D_OK;
6489 TRACE("Relaying to swapchain\n");
6491 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6492 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6493 IWineD3DSwapChain_Release(swapchain);
6495 return;
6498 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6499 IWineD3DSwapChain *swapchain;
6500 HRESULT hrc = WINED3D_OK;
6502 TRACE("Relaying to swapchain\n");
6504 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6505 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6506 IWineD3DSwapChain_Release(swapchain);
6508 return;
6512 /** ********************************************************
6513 * Notification functions
6514 ** ********************************************************/
6515 /** This function must be called in the release of a resource when ref == 0,
6516 * the contents of resource must still be correct,
6517 * any handels to other resource held by the caller must be closed
6518 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6519 *****************************************************/
6520 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6522 ResourceList* resourceList;
6524 TRACE("(%p) : resource %p\n", This, resource);
6525 /* add a new texture to the frot of the linked list */
6526 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6527 resourceList->resource = resource;
6529 /* Get the old head */
6530 resourceList->next = This->resources;
6532 This->resources = resourceList;
6533 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6535 return;
6538 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6540 ResourceList* resourceList = NULL;
6541 ResourceList* previousResourceList = NULL;
6543 TRACE("(%p) : resource %p\n", This, resource);
6545 resourceList = This->resources;
6547 while (resourceList != NULL) {
6548 if(resourceList->resource == resource) break;
6549 previousResourceList = resourceList;
6550 resourceList = resourceList->next;
6553 if (resourceList == NULL) {
6554 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6555 return;
6556 } else {
6557 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6559 /* make sure we don't leave a hole in the list */
6560 if (previousResourceList != NULL) {
6561 previousResourceList->next = resourceList->next;
6562 } else {
6563 This->resources = resourceList->next;
6566 return;
6570 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6572 int counter;
6574 TRACE("(%p) : resource %p\n", This, resource);
6575 switch(IWineD3DResource_GetType(resource)){
6576 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6577 case WINED3DRTYPE_SURFACE: {
6578 unsigned int i;
6580 /* Cleanup any FBO attachments if d3d is enabled */
6581 if(This->d3d_initialized) {
6582 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6583 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6584 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6585 set_render_target_fbo(iface, i, NULL);
6586 This->fbo_color_attachments[i] = NULL;
6589 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6590 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6591 set_depth_stencil_fbo(iface, NULL);
6592 This->fbo_depth_attachment = NULL;
6596 break;
6598 case WINED3DRTYPE_TEXTURE:
6599 case WINED3DRTYPE_CUBETEXTURE:
6600 case WINED3DRTYPE_VOLUMETEXTURE:
6601 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6602 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6603 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6604 This->stateBlock->textures[counter] = NULL;
6606 if (This->updateStateBlock != This->stateBlock ){
6607 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6608 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6609 This->updateStateBlock->textures[counter] = NULL;
6613 break;
6614 case WINED3DRTYPE_VOLUME:
6615 /* TODO: nothing really? */
6616 break;
6617 case WINED3DRTYPE_VERTEXBUFFER:
6618 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6620 int streamNumber;
6621 TRACE("Cleaning up stream pointers\n");
6623 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6624 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6625 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6627 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6628 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6629 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6630 This->updateStateBlock->streamSource[streamNumber] = 0;
6631 /* Set changed flag? */
6634 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) */
6635 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6636 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6637 This->stateBlock->streamSource[streamNumber] = 0;
6640 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6641 else { /* This shouldn't happen */
6642 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6644 #endif
6648 break;
6649 case WINED3DRTYPE_INDEXBUFFER:
6650 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6651 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6652 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6653 This->updateStateBlock->pIndexData = NULL;
6656 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6657 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6658 This->stateBlock->pIndexData = NULL;
6662 break;
6663 default:
6664 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6665 break;
6669 /* Remove the resoruce from the resourceStore */
6670 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6672 TRACE("Resource released\n");
6676 /**********************************************************
6677 * IWineD3DDevice VTbl follows
6678 **********************************************************/
6680 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6682 /*** IUnknown methods ***/
6683 IWineD3DDeviceImpl_QueryInterface,
6684 IWineD3DDeviceImpl_AddRef,
6685 IWineD3DDeviceImpl_Release,
6686 /*** IWineD3DDevice methods ***/
6687 IWineD3DDeviceImpl_GetParent,
6688 /*** Creation methods**/
6689 IWineD3DDeviceImpl_CreateVertexBuffer,
6690 IWineD3DDeviceImpl_CreateIndexBuffer,
6691 IWineD3DDeviceImpl_CreateStateBlock,
6692 IWineD3DDeviceImpl_CreateSurface,
6693 IWineD3DDeviceImpl_CreateTexture,
6694 IWineD3DDeviceImpl_CreateVolumeTexture,
6695 IWineD3DDeviceImpl_CreateVolume,
6696 IWineD3DDeviceImpl_CreateCubeTexture,
6697 IWineD3DDeviceImpl_CreateQuery,
6698 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6699 IWineD3DDeviceImpl_CreateVertexDeclaration,
6700 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6701 IWineD3DDeviceImpl_CreateVertexShader,
6702 IWineD3DDeviceImpl_CreatePixelShader,
6703 IWineD3DDeviceImpl_CreatePalette,
6704 /*** Odd functions **/
6705 IWineD3DDeviceImpl_Init3D,
6706 IWineD3DDeviceImpl_Uninit3D,
6707 IWineD3DDeviceImpl_SetFullscreen,
6708 IWineD3DDeviceImpl_SetMultithreaded,
6709 IWineD3DDeviceImpl_EvictManagedResources,
6710 IWineD3DDeviceImpl_GetAvailableTextureMem,
6711 IWineD3DDeviceImpl_GetBackBuffer,
6712 IWineD3DDeviceImpl_GetCreationParameters,
6713 IWineD3DDeviceImpl_GetDeviceCaps,
6714 IWineD3DDeviceImpl_GetDirect3D,
6715 IWineD3DDeviceImpl_GetDisplayMode,
6716 IWineD3DDeviceImpl_SetDisplayMode,
6717 IWineD3DDeviceImpl_GetHWND,
6718 IWineD3DDeviceImpl_SetHWND,
6719 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6720 IWineD3DDeviceImpl_GetRasterStatus,
6721 IWineD3DDeviceImpl_GetSwapChain,
6722 IWineD3DDeviceImpl_Reset,
6723 IWineD3DDeviceImpl_SetDialogBoxMode,
6724 IWineD3DDeviceImpl_SetCursorProperties,
6725 IWineD3DDeviceImpl_SetCursorPosition,
6726 IWineD3DDeviceImpl_ShowCursor,
6727 IWineD3DDeviceImpl_TestCooperativeLevel,
6728 /*** Getters and setters **/
6729 IWineD3DDeviceImpl_SetClipPlane,
6730 IWineD3DDeviceImpl_GetClipPlane,
6731 IWineD3DDeviceImpl_SetClipStatus,
6732 IWineD3DDeviceImpl_GetClipStatus,
6733 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6734 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6735 IWineD3DDeviceImpl_SetDepthStencilSurface,
6736 IWineD3DDeviceImpl_GetDepthStencilSurface,
6737 IWineD3DDeviceImpl_SetFVF,
6738 IWineD3DDeviceImpl_GetFVF,
6739 IWineD3DDeviceImpl_SetGammaRamp,
6740 IWineD3DDeviceImpl_GetGammaRamp,
6741 IWineD3DDeviceImpl_SetIndices,
6742 IWineD3DDeviceImpl_GetIndices,
6743 IWineD3DDeviceImpl_SetBaseVertexIndex,
6744 IWineD3DDeviceImpl_GetBaseVertexIndex,
6745 IWineD3DDeviceImpl_SetLight,
6746 IWineD3DDeviceImpl_GetLight,
6747 IWineD3DDeviceImpl_SetLightEnable,
6748 IWineD3DDeviceImpl_GetLightEnable,
6749 IWineD3DDeviceImpl_SetMaterial,
6750 IWineD3DDeviceImpl_GetMaterial,
6751 IWineD3DDeviceImpl_SetNPatchMode,
6752 IWineD3DDeviceImpl_GetNPatchMode,
6753 IWineD3DDeviceImpl_SetPaletteEntries,
6754 IWineD3DDeviceImpl_GetPaletteEntries,
6755 IWineD3DDeviceImpl_SetPixelShader,
6756 IWineD3DDeviceImpl_GetPixelShader,
6757 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6758 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6759 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6760 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6761 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6762 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6763 IWineD3DDeviceImpl_SetRenderState,
6764 IWineD3DDeviceImpl_GetRenderState,
6765 IWineD3DDeviceImpl_SetRenderTarget,
6766 IWineD3DDeviceImpl_GetRenderTarget,
6767 IWineD3DDeviceImpl_SetFrontBackBuffers,
6768 IWineD3DDeviceImpl_SetSamplerState,
6769 IWineD3DDeviceImpl_GetSamplerState,
6770 IWineD3DDeviceImpl_SetScissorRect,
6771 IWineD3DDeviceImpl_GetScissorRect,
6772 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6773 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6774 IWineD3DDeviceImpl_SetStreamSource,
6775 IWineD3DDeviceImpl_GetStreamSource,
6776 IWineD3DDeviceImpl_SetStreamSourceFreq,
6777 IWineD3DDeviceImpl_GetStreamSourceFreq,
6778 IWineD3DDeviceImpl_SetTexture,
6779 IWineD3DDeviceImpl_GetTexture,
6780 IWineD3DDeviceImpl_SetTextureStageState,
6781 IWineD3DDeviceImpl_GetTextureStageState,
6782 IWineD3DDeviceImpl_SetTransform,
6783 IWineD3DDeviceImpl_GetTransform,
6784 IWineD3DDeviceImpl_SetVertexDeclaration,
6785 IWineD3DDeviceImpl_GetVertexDeclaration,
6786 IWineD3DDeviceImpl_SetVertexShader,
6787 IWineD3DDeviceImpl_GetVertexShader,
6788 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6789 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6790 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6791 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6792 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6793 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6794 IWineD3DDeviceImpl_SetViewport,
6795 IWineD3DDeviceImpl_GetViewport,
6796 IWineD3DDeviceImpl_MultiplyTransform,
6797 IWineD3DDeviceImpl_ValidateDevice,
6798 IWineD3DDeviceImpl_ProcessVertices,
6799 /*** State block ***/
6800 IWineD3DDeviceImpl_BeginStateBlock,
6801 IWineD3DDeviceImpl_EndStateBlock,
6802 /*** Scene management ***/
6803 IWineD3DDeviceImpl_BeginScene,
6804 IWineD3DDeviceImpl_EndScene,
6805 IWineD3DDeviceImpl_Present,
6806 IWineD3DDeviceImpl_Clear,
6807 /*** Drawing ***/
6808 IWineD3DDeviceImpl_DrawPrimitive,
6809 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6810 IWineD3DDeviceImpl_DrawPrimitiveUP,
6811 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6812 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6813 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6814 IWineD3DDeviceImpl_DrawRectPatch,
6815 IWineD3DDeviceImpl_DrawTriPatch,
6816 IWineD3DDeviceImpl_DeletePatch,
6817 IWineD3DDeviceImpl_ColorFill,
6818 IWineD3DDeviceImpl_UpdateTexture,
6819 IWineD3DDeviceImpl_UpdateSurface,
6820 IWineD3DDeviceImpl_GetFrontBufferData,
6821 /*** object tracking ***/
6822 IWineD3DDeviceImpl_ResourceReleased
6826 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6827 WINED3DRS_ALPHABLENDENABLE ,
6828 WINED3DRS_ALPHAFUNC ,
6829 WINED3DRS_ALPHAREF ,
6830 WINED3DRS_ALPHATESTENABLE ,
6831 WINED3DRS_BLENDOP ,
6832 WINED3DRS_COLORWRITEENABLE ,
6833 WINED3DRS_DESTBLEND ,
6834 WINED3DRS_DITHERENABLE ,
6835 WINED3DRS_FILLMODE ,
6836 WINED3DRS_FOGDENSITY ,
6837 WINED3DRS_FOGEND ,
6838 WINED3DRS_FOGSTART ,
6839 WINED3DRS_LASTPIXEL ,
6840 WINED3DRS_SHADEMODE ,
6841 WINED3DRS_SRCBLEND ,
6842 WINED3DRS_STENCILENABLE ,
6843 WINED3DRS_STENCILFAIL ,
6844 WINED3DRS_STENCILFUNC ,
6845 WINED3DRS_STENCILMASK ,
6846 WINED3DRS_STENCILPASS ,
6847 WINED3DRS_STENCILREF ,
6848 WINED3DRS_STENCILWRITEMASK ,
6849 WINED3DRS_STENCILZFAIL ,
6850 WINED3DRS_TEXTUREFACTOR ,
6851 WINED3DRS_WRAP0 ,
6852 WINED3DRS_WRAP1 ,
6853 WINED3DRS_WRAP2 ,
6854 WINED3DRS_WRAP3 ,
6855 WINED3DRS_WRAP4 ,
6856 WINED3DRS_WRAP5 ,
6857 WINED3DRS_WRAP6 ,
6858 WINED3DRS_WRAP7 ,
6859 WINED3DRS_ZENABLE ,
6860 WINED3DRS_ZFUNC ,
6861 WINED3DRS_ZWRITEENABLE
6864 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6865 WINED3DTSS_ADDRESSW ,
6866 WINED3DTSS_ALPHAARG0 ,
6867 WINED3DTSS_ALPHAARG1 ,
6868 WINED3DTSS_ALPHAARG2 ,
6869 WINED3DTSS_ALPHAOP ,
6870 WINED3DTSS_BUMPENVLOFFSET ,
6871 WINED3DTSS_BUMPENVLSCALE ,
6872 WINED3DTSS_BUMPENVMAT00 ,
6873 WINED3DTSS_BUMPENVMAT01 ,
6874 WINED3DTSS_BUMPENVMAT10 ,
6875 WINED3DTSS_BUMPENVMAT11 ,
6876 WINED3DTSS_COLORARG0 ,
6877 WINED3DTSS_COLORARG1 ,
6878 WINED3DTSS_COLORARG2 ,
6879 WINED3DTSS_COLOROP ,
6880 WINED3DTSS_RESULTARG ,
6881 WINED3DTSS_TEXCOORDINDEX ,
6882 WINED3DTSS_TEXTURETRANSFORMFLAGS
6885 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6886 WINED3DSAMP_ADDRESSU ,
6887 WINED3DSAMP_ADDRESSV ,
6888 WINED3DSAMP_ADDRESSW ,
6889 WINED3DSAMP_BORDERCOLOR ,
6890 WINED3DSAMP_MAGFILTER ,
6891 WINED3DSAMP_MINFILTER ,
6892 WINED3DSAMP_MIPFILTER ,
6893 WINED3DSAMP_MIPMAPLODBIAS ,
6894 WINED3DSAMP_MAXMIPLEVEL ,
6895 WINED3DSAMP_MAXANISOTROPY ,
6896 WINED3DSAMP_SRGBTEXTURE ,
6897 WINED3DSAMP_ELEMENTINDEX
6900 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6901 WINED3DRS_AMBIENT ,
6902 WINED3DRS_AMBIENTMATERIALSOURCE ,
6903 WINED3DRS_CLIPPING ,
6904 WINED3DRS_CLIPPLANEENABLE ,
6905 WINED3DRS_COLORVERTEX ,
6906 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6907 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6908 WINED3DRS_FOGDENSITY ,
6909 WINED3DRS_FOGEND ,
6910 WINED3DRS_FOGSTART ,
6911 WINED3DRS_FOGTABLEMODE ,
6912 WINED3DRS_FOGVERTEXMODE ,
6913 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6914 WINED3DRS_LIGHTING ,
6915 WINED3DRS_LOCALVIEWER ,
6916 WINED3DRS_MULTISAMPLEANTIALIAS ,
6917 WINED3DRS_MULTISAMPLEMASK ,
6918 WINED3DRS_NORMALIZENORMALS ,
6919 WINED3DRS_PATCHEDGESTYLE ,
6920 WINED3DRS_POINTSCALE_A ,
6921 WINED3DRS_POINTSCALE_B ,
6922 WINED3DRS_POINTSCALE_C ,
6923 WINED3DRS_POINTSCALEENABLE ,
6924 WINED3DRS_POINTSIZE ,
6925 WINED3DRS_POINTSIZE_MAX ,
6926 WINED3DRS_POINTSIZE_MIN ,
6927 WINED3DRS_POINTSPRITEENABLE ,
6928 WINED3DRS_RANGEFOGENABLE ,
6929 WINED3DRS_SPECULARMATERIALSOURCE ,
6930 WINED3DRS_TWEENFACTOR ,
6931 WINED3DRS_VERTEXBLEND
6934 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6935 WINED3DTSS_TEXCOORDINDEX ,
6936 WINED3DTSS_TEXTURETRANSFORMFLAGS
6939 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6940 WINED3DSAMP_DMAPOFFSET
6943 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6944 DWORD rep = StateTable[state].representative;
6945 DWORD idx;
6946 BYTE shift;
6947 UINT i;
6948 WineD3DContext *context;
6950 if(!rep) return;
6951 for(i = 0; i < This->numContexts; i++) {
6952 context = This->contexts[i];
6953 if(isStateDirty(context, rep)) continue;
6955 context->dirtyArray[context->numDirtyEntries++] = rep;
6956 idx = rep >> 5;
6957 shift = rep & 0x1f;
6958 context->isStateDirty[idx] |= (1 << shift);