wined3d: Deal with multithreading in event queries.
[wine.git] / dlls / wined3d / device.c
blob850919255264ba6c8e6ccc34fe06ff5092753d67
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 break;
1145 case WINED3DQUERYTYPE_EVENT:
1146 if(GL_SUPPORT(APPLE_FENCE)) {
1147 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1148 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1149 checkGLcall("glGenFencesAPPLE");
1150 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1151 } else if(GL_SUPPORT(NV_FENCE)) {
1152 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1153 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1154 checkGLcall("glGenFencesNV");
1155 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1157 break;
1159 case WINED3DQUERYTYPE_VCACHE:
1160 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1161 case WINED3DQUERYTYPE_VERTEXSTATS:
1162 case WINED3DQUERYTYPE_TIMESTAMP:
1163 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1164 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1165 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1166 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1167 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1168 case WINED3DQUERYTYPE_PIXELTIMINGS:
1169 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1170 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1171 default:
1172 object->extendedData = 0;
1173 FIXME("(%p) Unhandled query type %d\n",This , Type);
1175 TRACE("(%p) : Created Query %p\n", This, object);
1176 return WINED3D_OK;
1179 /*****************************************************************************
1180 * IWineD3DDeviceImpl_SetupFullscreenWindow
1182 * Helper function that modifies a HWND's Style and ExStyle for proper
1183 * fullscreen use.
1185 * Params:
1186 * iface: Pointer to the IWineD3DDevice interface
1187 * window: Window to setup
1189 *****************************************************************************/
1190 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1193 LONG style, exStyle;
1194 /* Don't do anything if an original style is stored.
1195 * That shouldn't happen
1197 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1198 if (This->style || This->exStyle) {
1199 ERR("(%p): Want to change the window parameters of HWND %p, but "
1200 "another style is stored for restoration afterwards\n", This, window);
1203 /* Get the parameters and save them */
1204 style = GetWindowLongW(window, GWL_STYLE);
1205 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1206 This->style = style;
1207 This->exStyle = exStyle;
1209 /* Filter out window decorations */
1210 style &= ~WS_CAPTION;
1211 style &= ~WS_THICKFRAME;
1212 exStyle &= ~WS_EX_WINDOWEDGE;
1213 exStyle &= ~WS_EX_CLIENTEDGE;
1215 /* Make sure the window is managed, otherwise we won't get keyboard input */
1216 style |= WS_POPUP | WS_SYSMENU;
1218 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1219 This->style, This->exStyle, style, exStyle);
1221 SetWindowLongW(window, GWL_STYLE, style);
1222 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1224 /* Inform the window about the update. */
1225 SetWindowPos(window, HWND_TOP, 0, 0,
1226 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1227 ShowWindow(window, SW_NORMAL);
1230 /*****************************************************************************
1231 * IWineD3DDeviceImpl_RestoreWindow
1233 * Helper function that restores a windows' properties when taking it out
1234 * of fullscreen mode
1236 * Params:
1237 * iface: Pointer to the IWineD3DDevice interface
1238 * window: Window to setup
1240 *****************************************************************************/
1241 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1244 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1245 * switch, do nothing
1247 if (!This->style && !This->exStyle) return;
1249 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1250 This, window, This->style, This->exStyle);
1252 SetWindowLongW(window, GWL_STYLE, This->style);
1253 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1255 /* Delete the old values */
1256 This->style = 0;
1257 This->exStyle = 0;
1259 /* Inform the window about the update */
1260 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1261 0, 0, 0, 0, /* Pos, Size, ignored */
1262 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1265 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1266 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1267 IUnknown* parent,
1268 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1269 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1272 HDC hDc;
1273 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1274 HRESULT hr = WINED3D_OK;
1275 IUnknown *bufferParent;
1277 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1279 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1280 * does a device hold a reference to a swap chain giving them a lifetime of the device
1281 * or does the swap chain notify the device of its destruction.
1282 *******************************/
1284 /* Check the params */
1285 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1286 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1287 return WINED3DERR_INVALIDCALL;
1288 } else if (pPresentationParameters->BackBufferCount > 1) {
1289 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");
1292 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1294 /*********************
1295 * Lookup the window Handle and the relating X window handle
1296 ********************/
1298 /* Setup hwnd we are using, plus which display this equates to */
1299 object->win_handle = pPresentationParameters->hDeviceWindow;
1300 if (!object->win_handle) {
1301 object->win_handle = This->createParms.hFocusWindow;
1304 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1305 hDc = GetDC(object->win_handle);
1306 TRACE("Using hDc %p\n", hDc);
1308 if (NULL == hDc) {
1309 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1310 return WINED3DERR_NOTAVAILABLE;
1313 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1314 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1315 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1316 ReleaseDC(object->win_handle, hDc);
1318 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1319 * then the corresponding dimension of the client area of the hDeviceWindow
1320 * (or the focus window, if hDeviceWindow is NULL) is taken.
1321 **********************/
1323 if (pPresentationParameters->Windowed &&
1324 ((pPresentationParameters->BackBufferWidth == 0) ||
1325 (pPresentationParameters->BackBufferHeight == 0))) {
1327 RECT Rect;
1328 GetClientRect(object->win_handle, &Rect);
1330 if (pPresentationParameters->BackBufferWidth == 0) {
1331 pPresentationParameters->BackBufferWidth = Rect.right;
1332 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1334 if (pPresentationParameters->BackBufferHeight == 0) {
1335 pPresentationParameters->BackBufferHeight = Rect.bottom;
1336 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1340 /* Put the correct figures in the presentation parameters */
1341 TRACE("Copying across presentation parameters\n");
1342 object->presentParms = *pPresentationParameters;
1344 TRACE("calling rendertarget CB\n");
1345 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1346 parent,
1347 object->presentParms.BackBufferWidth,
1348 object->presentParms.BackBufferHeight,
1349 object->presentParms.BackBufferFormat,
1350 object->presentParms.MultiSampleType,
1351 object->presentParms.MultiSampleQuality,
1352 TRUE /* Lockable */,
1353 &object->frontBuffer,
1354 NULL /* pShared (always null)*/);
1355 if (object->frontBuffer != NULL) {
1356 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1357 } else {
1358 ERR("Failed to create the front buffer\n");
1359 goto error;
1363 * Create an opengl context for the display visual
1364 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1365 * use different properties after that point in time. FIXME: How to handle when requested format
1366 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1367 * it chooses is identical to the one already being used!
1368 **********************************/
1369 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1371 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1372 if(!object->context)
1373 return E_OUTOFMEMORY;
1374 object->num_contexts = 1;
1376 ENTER_GL();
1377 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1378 LEAVE_GL();
1380 if (!object->context[0]) {
1381 ERR("Failed to create a new context\n");
1382 hr = WINED3DERR_NOTAVAILABLE;
1383 goto error;
1384 } else {
1385 TRACE("Context created (HWND=%p, glContext=%p)\n",
1386 object->win_handle, object->context[0]->glCtx);
1389 /*********************
1390 * Windowed / Fullscreen
1391 *******************/
1394 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1395 * so we should really check to see if there is a fullscreen swapchain already
1396 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1397 **************************************/
1399 if (!pPresentationParameters->Windowed) {
1401 DEVMODEW devmode;
1402 HDC hdc;
1403 int bpp = 0;
1404 RECT clip_rc;
1406 /* Get info on the current display setup */
1407 hdc = GetDC(0);
1408 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1409 ReleaseDC(0, hdc);
1411 /* Change the display settings */
1412 memset(&devmode, 0, sizeof(devmode));
1413 devmode.dmSize = sizeof(devmode);
1414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1415 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1416 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1417 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1418 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1420 /* For GetDisplayMode */
1421 This->ddraw_width = devmode.dmPelsWidth;
1422 This->ddraw_height = devmode.dmPelsHeight;
1423 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1425 IWineD3DDevice_SetFullscreen(iface, TRUE);
1427 /* And finally clip mouse to our screen */
1428 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1429 ClipCursor(&clip_rc);
1432 /*********************
1433 * Create the back, front and stencil buffers
1434 *******************/
1435 if(object->presentParms.BackBufferCount > 0) {
1436 int i;
1438 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1439 if(!object->backBuffer) {
1440 ERR("Out of memory\n");
1441 hr = E_OUTOFMEMORY;
1442 goto error;
1445 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1446 TRACE("calling rendertarget CB\n");
1447 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1448 parent,
1449 object->presentParms.BackBufferWidth,
1450 object->presentParms.BackBufferHeight,
1451 object->presentParms.BackBufferFormat,
1452 object->presentParms.MultiSampleType,
1453 object->presentParms.MultiSampleQuality,
1454 TRUE /* Lockable */,
1455 &object->backBuffer[i],
1456 NULL /* pShared (always null)*/);
1457 if(hr == WINED3D_OK && object->backBuffer[i]) {
1458 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1459 } else {
1460 ERR("Cannot create new back buffer\n");
1461 goto error;
1463 ENTER_GL();
1464 glDrawBuffer(GL_BACK);
1465 checkGLcall("glDrawBuffer(GL_BACK)");
1466 LEAVE_GL();
1468 } else {
1469 object->backBuffer = NULL;
1471 /* Single buffering - draw to front buffer */
1472 ENTER_GL();
1473 glDrawBuffer(GL_FRONT);
1474 checkGLcall("glDrawBuffer(GL_FRONT)");
1475 LEAVE_GL();
1478 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1479 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1480 TRACE("Creating depth stencil buffer\n");
1481 if (This->depthStencilBuffer == NULL ) {
1482 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1483 parent,
1484 object->presentParms.BackBufferWidth,
1485 object->presentParms.BackBufferHeight,
1486 object->presentParms.AutoDepthStencilFormat,
1487 object->presentParms.MultiSampleType,
1488 object->presentParms.MultiSampleQuality,
1489 FALSE /* FIXME: Discard */,
1490 &This->depthStencilBuffer,
1491 NULL /* pShared (always null)*/ );
1492 if (This->depthStencilBuffer != NULL)
1493 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1496 /** TODO: A check on width, height and multisample types
1497 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1498 ****************************/
1499 object->wantsDepthStencilBuffer = TRUE;
1500 } else {
1501 object->wantsDepthStencilBuffer = FALSE;
1504 TRACE("Created swapchain %p\n", object);
1505 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1506 return WINED3D_OK;
1508 error:
1509 if (object->backBuffer) {
1510 int i;
1511 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1512 if(object->backBuffer[i]) {
1513 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1514 IUnknown_Release(bufferParent); /* once for the get parent */
1515 if (IUnknown_Release(bufferParent) > 0) {
1516 FIXME("(%p) Something's still holding the back buffer\n",This);
1520 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1521 object->backBuffer = NULL;
1523 if(object->context[0])
1524 DestroyContext(This, object->context[0]);
1525 if(object->frontBuffer) {
1526 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1527 IUnknown_Release(bufferParent); /* once for the get parent */
1528 if (IUnknown_Release(bufferParent) > 0) {
1529 FIXME("(%p) Something's still holding the front buffer\n",This);
1532 HeapFree(GetProcessHeap(), 0, object);
1533 return hr;
1536 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1537 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1539 TRACE("(%p)\n", This);
1541 return This->NumberOfSwapChains;
1544 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1546 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1548 if(iSwapChain < This->NumberOfSwapChains) {
1549 *pSwapChain = This->swapchains[iSwapChain];
1550 IWineD3DSwapChain_AddRef(*pSwapChain);
1551 TRACE("(%p) returning %p\n", This, *pSwapChain);
1552 return WINED3D_OK;
1553 } else {
1554 TRACE("Swapchain out of range\n");
1555 *pSwapChain = NULL;
1556 return WINED3DERR_INVALIDCALL;
1560 /*****
1561 * Vertex Declaration
1562 *****/
1563 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1564 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1566 IWineD3DVertexDeclarationImpl *object = NULL;
1567 HRESULT hr = WINED3D_OK;
1569 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1570 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1572 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1574 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1576 return hr;
1579 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1581 unsigned int idx, idx2;
1582 unsigned int offset;
1583 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1584 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1585 BOOL has_blend_idx = has_blend &&
1586 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1587 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1588 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1589 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1590 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1591 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1592 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1594 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1595 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1597 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1598 WINED3DVERTEXELEMENT *elements = NULL;
1600 unsigned int size;
1601 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1602 if (has_blend_idx) num_blends--;
1604 /* Compute declaration size */
1605 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1606 has_psize + has_diffuse + has_specular + num_textures + 1;
1608 /* convert the declaration */
1609 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1610 if (!elements)
1611 return 0;
1613 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1614 idx = 0;
1615 if (has_pos) {
1616 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1617 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1618 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1620 else {
1621 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1622 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1624 elements[idx].UsageIndex = 0;
1625 idx++;
1627 if (has_blend && (num_blends > 0)) {
1628 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1629 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1630 else
1631 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1632 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1633 elements[idx].UsageIndex = 0;
1634 idx++;
1636 if (has_blend_idx) {
1637 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1638 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1639 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1640 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1641 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1642 else
1643 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1644 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1645 elements[idx].UsageIndex = 0;
1646 idx++;
1648 if (has_normal) {
1649 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1650 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1651 elements[idx].UsageIndex = 0;
1652 idx++;
1654 if (has_psize) {
1655 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1656 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1657 elements[idx].UsageIndex = 0;
1658 idx++;
1660 if (has_diffuse) {
1661 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1662 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1663 elements[idx].UsageIndex = 0;
1664 idx++;
1666 if (has_specular) {
1667 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1668 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1669 elements[idx].UsageIndex = 1;
1670 idx++;
1672 for (idx2 = 0; idx2 < num_textures; idx2++) {
1673 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1674 switch (numcoords) {
1675 case WINED3DFVF_TEXTUREFORMAT1:
1676 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1677 break;
1678 case WINED3DFVF_TEXTUREFORMAT2:
1679 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1680 break;
1681 case WINED3DFVF_TEXTUREFORMAT3:
1682 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1683 break;
1684 case WINED3DFVF_TEXTUREFORMAT4:
1685 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1686 break;
1688 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1689 elements[idx].UsageIndex = idx2;
1690 idx++;
1693 /* Now compute offsets, and initialize the rest of the fields */
1694 for (idx = 0, offset = 0; idx < size-1; idx++) {
1695 elements[idx].Stream = 0;
1696 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1697 elements[idx].Offset = offset;
1698 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1701 *ppVertexElements = elements;
1702 return size;
1705 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1706 WINED3DVERTEXELEMENT* elements = NULL;
1707 size_t size;
1708 DWORD hr;
1710 size = ConvertFvfToDeclaration(Fvf, &elements);
1711 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1713 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1714 HeapFree(GetProcessHeap(), 0, elements);
1715 if (hr != S_OK) return hr;
1717 return WINED3D_OK;
1720 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1721 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1723 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1724 HRESULT hr = WINED3D_OK;
1725 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1726 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1728 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1730 if (vertex_declaration) {
1731 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1734 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1736 if (WINED3D_OK != hr) {
1737 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1738 IWineD3DVertexShader_Release(*ppVertexShader);
1739 return WINED3DERR_INVALIDCALL;
1742 return WINED3D_OK;
1745 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1747 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1748 HRESULT hr = WINED3D_OK;
1750 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1751 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1752 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1753 if (WINED3D_OK == hr) {
1754 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1755 } else {
1756 WARN("(%p) : Failed to create pixel shader\n", This);
1759 return hr;
1762 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1764 IWineD3DPaletteImpl *object;
1765 HRESULT hr;
1766 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1768 /* Create the new object */
1769 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1770 if(!object) {
1771 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1772 return E_OUTOFMEMORY;
1775 object->lpVtbl = &IWineD3DPalette_Vtbl;
1776 object->ref = 1;
1777 object->Flags = Flags;
1778 object->parent = Parent;
1779 object->wineD3DDevice = This;
1780 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1782 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1784 if(!object->hpal) {
1785 HeapFree( GetProcessHeap(), 0, object);
1786 return E_OUTOFMEMORY;
1789 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1790 if(FAILED(hr)) {
1791 IWineD3DPalette_Release((IWineD3DPalette *) object);
1792 return hr;
1795 *Palette = (IWineD3DPalette *) object;
1797 return WINED3D_OK;
1800 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1801 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1802 IWineD3DSwapChainImpl *swapchain;
1803 HRESULT hr;
1804 DWORD state;
1806 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1807 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1809 /* TODO: Test if OpenGL is compiled in and loaded */
1811 TRACE("(%p) : Creating stateblock\n", This);
1812 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1813 hr = IWineD3DDevice_CreateStateBlock(iface,
1814 WINED3DSBT_INIT,
1815 (IWineD3DStateBlock **)&This->stateBlock,
1816 NULL);
1817 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1818 WARN("Failed to create stateblock\n");
1819 return hr;
1821 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1822 This->updateStateBlock = This->stateBlock;
1823 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1825 hr = allocate_shader_constants(This->updateStateBlock);
1826 if (WINED3D_OK != hr)
1827 return hr;
1829 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1830 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1831 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1833 /* Initialize the texture unit mapping to a 1:1 mapping */
1834 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1835 if (state < GL_LIMITS(fragment_samplers)) {
1836 This->texUnitMap[state] = state;
1837 This->rev_tex_unit_map[state] = state;
1838 } else {
1839 This->texUnitMap[state] = -1;
1840 This->rev_tex_unit_map[state] = -1;
1844 /* Setup the implicit swapchain */
1845 TRACE("Creating implicit swapchain\n");
1846 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1847 if (FAILED(hr) || !swapchain) {
1848 WARN("Failed to create implicit swapchain\n");
1849 return hr;
1852 This->NumberOfSwapChains = 1;
1853 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1854 if(!This->swapchains) {
1855 ERR("Out of memory!\n");
1856 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1857 return E_OUTOFMEMORY;
1859 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1861 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1863 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1864 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1865 This->render_targets[0] = swapchain->backBuffer[0];
1866 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1868 else {
1869 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1870 This->render_targets[0] = swapchain->frontBuffer;
1871 This->lastActiveRenderTarget = swapchain->frontBuffer;
1873 IWineD3DSurface_AddRef(This->render_targets[0]);
1874 This->activeContext = swapchain->context[0];
1875 This->lastThread = GetCurrentThreadId();
1877 /* Depth Stencil support */
1878 This->stencilBufferTarget = This->depthStencilBuffer;
1879 if (NULL != This->stencilBufferTarget) {
1880 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1883 /* Set up some starting GL setup */
1884 ENTER_GL();
1886 /* Setup all the devices defaults */
1887 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1888 #if 0
1889 IWineD3DImpl_CheckGraphicsMemory();
1890 #endif
1892 { /* Set a default viewport */
1893 WINED3DVIEWPORT vp;
1894 vp.X = 0;
1895 vp.Y = 0;
1896 vp.Width = pPresentationParameters->BackBufferWidth;
1897 vp.Height = pPresentationParameters->BackBufferHeight;
1898 vp.MinZ = 0.0f;
1899 vp.MaxZ = 1.0f;
1900 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1903 /* Initialize the current view state */
1904 This->view_ident = 1;
1905 This->contexts[0]->last_was_rhw = 0;
1906 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1907 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1909 switch(wined3d_settings.offscreen_rendering_mode) {
1910 case ORM_FBO:
1911 case ORM_PBUFFER:
1912 This->offscreenBuffer = GL_BACK;
1913 break;
1915 case ORM_BACKBUFFER:
1917 if(GL_LIMITS(aux_buffers) > 0) {
1918 TRACE("Using auxilliary buffer for offscreen rendering\n");
1919 This->offscreenBuffer = GL_AUX0;
1920 } else {
1921 TRACE("Using back buffer for offscreen rendering\n");
1922 This->offscreenBuffer = GL_BACK;
1927 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1928 LEAVE_GL();
1930 /* Clear the screen */
1931 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1932 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1933 0x00, 1.0, 0);
1935 This->d3d_initialized = TRUE;
1936 return WINED3D_OK;
1939 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1941 int sampler;
1942 UINT i;
1943 TRACE("(%p)\n", This);
1945 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1947 /* I don't think that the interface guarants that the device is destroyed from the same thread
1948 * it was created. Thus make sure a context is active for the glDelete* calls
1950 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1952 TRACE("Deleting high order patches\n");
1953 for(i = 0; i < PATCHMAP_SIZE; i++) {
1954 struct list *e1, *e2;
1955 struct WineD3DRectPatch *patch;
1956 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1957 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1958 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1962 /* Delete the pbuffer context if there is any */
1963 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1965 /* Delete the mouse cursor texture */
1966 if(This->cursorTexture) {
1967 ENTER_GL();
1968 glDeleteTextures(1, &This->cursorTexture);
1969 LEAVE_GL();
1970 This->cursorTexture = 0;
1973 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1974 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1976 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1977 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1980 /* Release the update stateblock */
1981 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1982 if(This->updateStateBlock != This->stateBlock)
1983 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1985 This->updateStateBlock = NULL;
1987 { /* because were not doing proper internal refcounts releasing the primary state block
1988 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1989 to set this->stateBlock = NULL; first */
1990 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1991 This->stateBlock = NULL;
1993 /* Release the stateblock */
1994 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1995 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1999 /* Release the buffers (with sanity checks)*/
2000 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2001 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2002 if(This->depthStencilBuffer != This->stencilBufferTarget)
2003 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2005 This->stencilBufferTarget = NULL;
2007 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2008 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2009 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2011 TRACE("Setting rendertarget to NULL\n");
2012 This->render_targets[0] = NULL;
2014 if (This->depthStencilBuffer) {
2015 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2016 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2018 This->depthStencilBuffer = NULL;
2021 for(i=0; i < This->NumberOfSwapChains; i++) {
2022 TRACE("Releasing the implicit swapchain %d\n", i);
2023 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2024 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2028 HeapFree(GetProcessHeap(), 0, This->swapchains);
2029 This->swapchains = NULL;
2030 This->NumberOfSwapChains = 0;
2032 HeapFree(GetProcessHeap(), 0, This->render_targets);
2033 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2034 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2035 This->render_targets = NULL;
2036 This->fbo_color_attachments = NULL;
2037 This->draw_buffers = NULL;
2040 This->d3d_initialized = FALSE;
2041 return WINED3D_OK;
2044 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2046 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2048 /* Setup the window for fullscreen mode */
2049 if(fullscreen && !This->ddraw_fullscreen) {
2050 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2051 } else if(!fullscreen && This->ddraw_fullscreen) {
2052 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2055 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2056 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2057 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2058 * separately.
2060 This->ddraw_fullscreen = fullscreen;
2063 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2064 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2065 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2067 * There is no way to deactivate thread safety once it is enabled
2069 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2072 /*For now just store the flag(needed in case of ddraw) */
2073 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2075 return;
2078 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2079 DEVMODEW devmode;
2080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2081 LONG ret;
2082 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2083 RECT clip_rc;
2085 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2087 /* Resize the screen even without a window:
2088 * The app could have unset it with SetCooperativeLevel, but not called
2089 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2090 * but we don't have any hwnd
2093 memset(&devmode, 0, sizeof(devmode));
2094 devmode.dmSize = sizeof(devmode);
2095 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2096 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2097 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2098 devmode.dmPelsWidth = pMode->Width;
2099 devmode.dmPelsHeight = pMode->Height;
2101 devmode.dmDisplayFrequency = pMode->RefreshRate;
2102 if (pMode->RefreshRate != 0) {
2103 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2106 /* Only change the mode if necessary */
2107 if( (This->ddraw_width == pMode->Width) &&
2108 (This->ddraw_height == pMode->Height) &&
2109 (This->ddraw_format == pMode->Format) &&
2110 (pMode->RefreshRate == 0) ) {
2111 return WINED3D_OK;
2114 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2115 if (ret != DISP_CHANGE_SUCCESSFUL) {
2116 if(devmode.dmDisplayFrequency != 0) {
2117 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2118 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2119 devmode.dmDisplayFrequency = 0;
2120 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2122 if(ret != DISP_CHANGE_SUCCESSFUL) {
2123 return WINED3DERR_NOTAVAILABLE;
2127 /* Store the new values */
2128 This->ddraw_width = pMode->Width;
2129 This->ddraw_height = pMode->Height;
2130 This->ddraw_format = pMode->Format;
2132 /* Only do this with a window of course */
2133 if(This->ddraw_window)
2134 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2136 /* And finally clip mouse to our screen */
2137 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2138 ClipCursor(&clip_rc);
2140 return WINED3D_OK;
2143 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2145 *ppD3D= This->wineD3D;
2146 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2147 IWineD3D_AddRef(*ppD3D);
2148 return WINED3D_OK;
2151 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2152 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2153 * into the video ram as possible and seeing how many fit
2154 * you can also get the correct initial value from nvidia and ATI's driver via X
2155 * texture memory is video memory + AGP memory
2156 *******************/
2157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2158 static BOOL showfixmes = TRUE;
2159 if (showfixmes) {
2160 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2161 (wined3d_settings.emulated_textureram/(1024*1024)),
2162 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2163 showfixmes = FALSE;
2165 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2166 (wined3d_settings.emulated_textureram/(1024*1024)),
2167 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2168 /* return simulated texture memory left */
2169 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2174 /*****
2175 * Get / Set FVF
2176 *****/
2177 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2180 /* Update the current state block */
2181 This->updateStateBlock->changed.fvf = TRUE;
2183 if(This->updateStateBlock->fvf == fvf) {
2184 TRACE("Application is setting the old fvf over, nothing to do\n");
2185 return WINED3D_OK;
2188 This->updateStateBlock->fvf = fvf;
2189 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2190 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2191 return WINED3D_OK;
2195 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2197 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2198 *pfvf = This->stateBlock->fvf;
2199 return WINED3D_OK;
2202 /*****
2203 * Get / Set Stream Source
2204 *****/
2205 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2207 IWineD3DVertexBuffer *oldSrc;
2209 if (StreamNumber >= MAX_STREAMS) {
2210 WARN("Stream out of range %d\n", StreamNumber);
2211 return WINED3DERR_INVALIDCALL;
2214 oldSrc = This->stateBlock->streamSource[StreamNumber];
2215 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2217 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2219 if(oldSrc == pStreamData &&
2220 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2221 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2222 TRACE("Application is setting the old values over, nothing to do\n");
2223 return WINED3D_OK;
2226 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2227 if (pStreamData) {
2228 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2229 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2232 /* Handle recording of state blocks */
2233 if (This->isRecordingState) {
2234 TRACE("Recording... not performing anything\n");
2235 return WINED3D_OK;
2238 /* Need to do a getParent and pass the reffs up */
2239 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2240 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2241 so for now, just count internally */
2242 if (pStreamData != NULL) {
2243 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2244 InterlockedIncrement(&vbImpl->bindCount);
2245 IWineD3DVertexBuffer_AddRef(pStreamData);
2247 if (oldSrc != NULL) {
2248 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2249 IWineD3DVertexBuffer_Release(oldSrc);
2252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2254 return WINED3D_OK;
2257 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2260 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2261 This->stateBlock->streamSource[StreamNumber],
2262 This->stateBlock->streamOffset[StreamNumber],
2263 This->stateBlock->streamStride[StreamNumber]);
2265 if (StreamNumber >= MAX_STREAMS) {
2266 WARN("Stream out of range %d\n", StreamNumber);
2267 return WINED3DERR_INVALIDCALL;
2269 *pStream = This->stateBlock->streamSource[StreamNumber];
2270 *pStride = This->stateBlock->streamStride[StreamNumber];
2271 if (pOffset) {
2272 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2275 if (*pStream != NULL) {
2276 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2278 return WINED3D_OK;
2281 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2284 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2286 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2287 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2289 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2290 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2292 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2293 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2294 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2297 return WINED3D_OK;
2300 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2303 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2304 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2306 TRACE("(%p) : returning %d\n", This, *Divider);
2308 return WINED3D_OK;
2311 /*****
2312 * Get / Set & Multiply Transform
2313 *****/
2314 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2315 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2317 /* Most of this routine, comments included copied from ddraw tree initially: */
2318 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2320 /* Handle recording of state blocks */
2321 if (This->isRecordingState) {
2322 TRACE("Recording... not performing anything\n");
2323 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2324 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2325 return WINED3D_OK;
2329 * If the new matrix is the same as the current one,
2330 * we cut off any further processing. this seems to be a reasonable
2331 * optimization because as was noticed, some apps (warcraft3 for example)
2332 * tend towards setting the same matrix repeatedly for some reason.
2334 * From here on we assume that the new matrix is different, wherever it matters.
2336 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2337 TRACE("The app is setting the same matrix over again\n");
2338 return WINED3D_OK;
2339 } else {
2340 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2344 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2345 where ViewMat = Camera space, WorldMat = world space.
2347 In OpenGL, camera and world space is combined into GL_MODELVIEW
2348 matrix. The Projection matrix stay projection matrix.
2351 /* Capture the times we can just ignore the change for now */
2352 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2353 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2354 /* Handled by the state manager */
2357 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2358 return WINED3D_OK;
2361 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2363 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2364 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2365 return WINED3D_OK;
2368 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2369 WINED3DMATRIX *mat = NULL;
2370 WINED3DMATRIX temp;
2372 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2373 * below means it will be recorded in a state block change, but it
2374 * works regardless where it is recorded.
2375 * If this is found to be wrong, change to StateBlock.
2377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2378 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2380 if (State < HIGHEST_TRANSFORMSTATE)
2382 mat = &This->updateStateBlock->transforms[State];
2383 } else {
2384 FIXME("Unhandled transform state!!\n");
2387 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2389 /* Apply change via set transform - will reapply to eg. lights this way */
2390 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2393 /*****
2394 * Get / Set Light
2395 *****/
2396 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2397 you can reference any indexes you want as long as that number max are enabled at any
2398 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2399 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2400 but when recording, just build a chain pretty much of commands to be replayed. */
2402 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2403 float rho;
2404 PLIGHTINFOEL *object = NULL;
2405 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2406 struct list *e;
2408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2409 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2411 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2412 * the gl driver.
2414 if(!pLight) {
2415 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2416 return WINED3DERR_INVALIDCALL;
2419 switch(pLight->Type) {
2420 case WINED3DLIGHT_POINT:
2421 case WINED3DLIGHT_SPOT:
2422 case WINED3DLIGHT_PARALLELPOINT:
2423 case WINED3DLIGHT_GLSPOT:
2424 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2425 * most wanted
2427 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2428 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2429 return WINED3DERR_INVALIDCALL;
2431 break;
2433 case WINED3DLIGHT_DIRECTIONAL:
2434 /* Ignores attenuation */
2435 break;
2437 default:
2438 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2439 return WINED3DERR_INVALIDCALL;
2442 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2443 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2444 if(object->OriginalIndex == Index) break;
2445 object = NULL;
2448 if(!object) {
2449 TRACE("Adding new light\n");
2450 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2451 if(!object) {
2452 ERR("Out of memory error when allocating a light\n");
2453 return E_OUTOFMEMORY;
2455 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2456 object->glIndex = -1;
2457 object->OriginalIndex = Index;
2458 object->changed = TRUE;
2461 /* Initialize the object */
2462 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,
2463 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2464 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2465 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2466 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2467 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2468 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2470 /* Save away the information */
2471 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2473 switch (pLight->Type) {
2474 case WINED3DLIGHT_POINT:
2475 /* Position */
2476 object->lightPosn[0] = pLight->Position.x;
2477 object->lightPosn[1] = pLight->Position.y;
2478 object->lightPosn[2] = pLight->Position.z;
2479 object->lightPosn[3] = 1.0f;
2480 object->cutoff = 180.0f;
2481 /* FIXME: Range */
2482 break;
2484 case WINED3DLIGHT_DIRECTIONAL:
2485 /* Direction */
2486 object->lightPosn[0] = -pLight->Direction.x;
2487 object->lightPosn[1] = -pLight->Direction.y;
2488 object->lightPosn[2] = -pLight->Direction.z;
2489 object->lightPosn[3] = 0.0;
2490 object->exponent = 0.0f;
2491 object->cutoff = 180.0f;
2492 break;
2494 case WINED3DLIGHT_SPOT:
2495 /* Position */
2496 object->lightPosn[0] = pLight->Position.x;
2497 object->lightPosn[1] = pLight->Position.y;
2498 object->lightPosn[2] = pLight->Position.z;
2499 object->lightPosn[3] = 1.0;
2501 /* Direction */
2502 object->lightDirn[0] = pLight->Direction.x;
2503 object->lightDirn[1] = pLight->Direction.y;
2504 object->lightDirn[2] = pLight->Direction.z;
2505 object->lightDirn[3] = 1.0;
2508 * opengl-ish and d3d-ish spot lights use too different models for the
2509 * light "intensity" as a function of the angle towards the main light direction,
2510 * so we only can approximate very roughly.
2511 * however spot lights are rather rarely used in games (if ever used at all).
2512 * furthermore if still used, probably nobody pays attention to such details.
2514 if (pLight->Falloff == 0) {
2515 rho = 6.28f;
2516 } else {
2517 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2519 if (rho < 0.0001) rho = 0.0001f;
2520 object->exponent = -0.3/log(cos(rho/2));
2521 if (object->exponent > 128.0) {
2522 object->exponent = 128.0;
2524 object->cutoff = pLight->Phi*90/M_PI;
2526 /* FIXME: Range */
2527 break;
2529 default:
2530 FIXME("Unrecognized light type %d\n", pLight->Type);
2533 /* Update the live definitions if the light is currently assigned a glIndex */
2534 if (object->glIndex != -1 && !This->isRecordingState) {
2535 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2537 return WINED3D_OK;
2540 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2541 PLIGHTINFOEL *lightInfo = NULL;
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2543 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2544 struct list *e;
2545 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2547 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2548 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2549 if(lightInfo->OriginalIndex == Index) break;
2550 lightInfo = NULL;
2553 if (lightInfo == NULL) {
2554 TRACE("Light information requested but light not defined\n");
2555 return WINED3DERR_INVALIDCALL;
2558 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2559 return WINED3D_OK;
2562 /*****
2563 * Get / Set Light Enable
2564 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2567 PLIGHTINFOEL *lightInfo = NULL;
2568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2570 struct list *e;
2571 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2573 /* Tests show true = 128...not clear why */
2574 Enable = Enable? 128: 0;
2576 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2577 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2578 if(lightInfo->OriginalIndex == Index) break;
2579 lightInfo = NULL;
2581 TRACE("Found light: %p\n", lightInfo);
2583 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2584 if (lightInfo == NULL) {
2586 TRACE("Light enabled requested but light not defined, so defining one!\n");
2587 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2589 /* Search for it again! Should be fairly quick as near head of list */
2590 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2591 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2592 if(lightInfo->OriginalIndex == Index) break;
2593 lightInfo = NULL;
2595 if (lightInfo == NULL) {
2596 FIXME("Adding default lights has failed dismally\n");
2597 return WINED3DERR_INVALIDCALL;
2601 lightInfo->enabledChanged = TRUE;
2602 if(!Enable) {
2603 if(lightInfo->glIndex != -1) {
2604 if(!This->isRecordingState) {
2605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2608 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2609 lightInfo->glIndex = -1;
2610 } else {
2611 TRACE("Light already disabled, nothing to do\n");
2613 } else {
2614 if (lightInfo->glIndex != -1) {
2615 /* nop */
2616 TRACE("Nothing to do as light was enabled\n");
2617 } else {
2618 int i;
2619 /* Find a free gl light */
2620 for(i = 0; i < This->maxConcurrentLights; i++) {
2621 if(This->stateBlock->activeLights[i] == NULL) {
2622 This->stateBlock->activeLights[i] = lightInfo;
2623 lightInfo->glIndex = i;
2624 break;
2627 if(lightInfo->glIndex == -1) {
2628 ERR("Too many concurrently active lights\n");
2629 return WINED3DERR_INVALIDCALL;
2632 /* i == lightInfo->glIndex */
2633 if(!This->isRecordingState) {
2634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2639 return WINED3D_OK;
2642 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2644 PLIGHTINFOEL *lightInfo = NULL;
2645 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2646 struct list *e;
2647 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2648 TRACE("(%p) : for idx(%d)\n", This, Index);
2650 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2651 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2652 if(lightInfo->OriginalIndex == Index) break;
2653 lightInfo = NULL;
2656 if (lightInfo == NULL) {
2657 TRACE("Light enabled state requested but light not defined\n");
2658 return WINED3DERR_INVALIDCALL;
2660 /* true is 128 according to SetLightEnable */
2661 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2662 return WINED3D_OK;
2665 /*****
2666 * Get / Set Clip Planes
2667 *****/
2668 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2670 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2672 /* Validate Index */
2673 if (Index >= GL_LIMITS(clipplanes)) {
2674 TRACE("Application has requested clipplane this device doesn't support\n");
2675 return WINED3DERR_INVALIDCALL;
2678 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2680 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2681 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2682 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2683 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2684 TRACE("Application is setting old values over, nothing to do\n");
2685 return WINED3D_OK;
2688 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2689 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2690 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2691 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2693 /* Handle recording of state blocks */
2694 if (This->isRecordingState) {
2695 TRACE("Recording... not performing anything\n");
2696 return WINED3D_OK;
2699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2701 return WINED3D_OK;
2704 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2706 TRACE("(%p) : for idx %d\n", This, Index);
2708 /* Validate Index */
2709 if (Index >= GL_LIMITS(clipplanes)) {
2710 TRACE("Application has requested clipplane this device doesn't support\n");
2711 return WINED3DERR_INVALIDCALL;
2714 pPlane[0] = This->stateBlock->clipplane[Index][0];
2715 pPlane[1] = This->stateBlock->clipplane[Index][1];
2716 pPlane[2] = This->stateBlock->clipplane[Index][2];
2717 pPlane[3] = This->stateBlock->clipplane[Index][3];
2718 return WINED3D_OK;
2721 /*****
2722 * Get / Set Clip Plane Status
2723 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2724 *****/
2725 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 FIXME("(%p) : stub\n", This);
2728 if (NULL == pClipStatus) {
2729 return WINED3DERR_INVALIDCALL;
2731 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2732 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2733 return WINED3D_OK;
2736 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2738 FIXME("(%p) : stub\n", This);
2739 if (NULL == pClipStatus) {
2740 return WINED3DERR_INVALIDCALL;
2742 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2743 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2744 return WINED3D_OK;
2747 /*****
2748 * Get / Set Material
2749 *****/
2750 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 This->updateStateBlock->changed.material = TRUE;
2754 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2756 /* Handle recording of state blocks */
2757 if (This->isRecordingState) {
2758 TRACE("Recording... not performing anything\n");
2759 return WINED3D_OK;
2762 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2763 return WINED3D_OK;
2766 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2769 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2770 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2771 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2772 pMaterial->Ambient.b, pMaterial->Ambient.a);
2773 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2774 pMaterial->Specular.b, pMaterial->Specular.a);
2775 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2776 pMaterial->Emissive.b, pMaterial->Emissive.a);
2777 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2779 return WINED3D_OK;
2782 /*****
2783 * Get / Set Indices
2784 *****/
2785 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 IWineD3DIndexBuffer *oldIdxs;
2789 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2790 oldIdxs = This->updateStateBlock->pIndexData;
2792 This->updateStateBlock->changed.indices = TRUE;
2793 This->updateStateBlock->pIndexData = pIndexData;
2795 /* Handle recording of state blocks */
2796 if (This->isRecordingState) {
2797 TRACE("Recording... not performing anything\n");
2798 return WINED3D_OK;
2801 if(oldIdxs != pIndexData) {
2802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2803 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2804 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2806 return WINED3D_OK;
2809 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2810 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2812 *ppIndexData = This->stateBlock->pIndexData;
2814 /* up ref count on ppindexdata */
2815 if (*ppIndexData) {
2816 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2817 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2818 }else{
2819 TRACE("(%p) No index data set\n", This);
2821 TRACE("Returning %p\n", *ppIndexData);
2823 return WINED3D_OK;
2826 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2827 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2829 TRACE("(%p)->(%d)\n", This, BaseIndex);
2831 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2832 TRACE("Application is setting the old value over, nothing to do\n");
2833 return WINED3D_OK;
2836 This->updateStateBlock->baseVertexIndex = BaseIndex;
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2840 return WINED3D_OK;
2842 /* The base vertex index affects the stream sources */
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2844 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 TRACE("(%p) : base_index %p\n", This, base_index);
2851 *base_index = This->stateBlock->baseVertexIndex;
2853 TRACE("Returning %u\n", *base_index);
2855 return WINED3D_OK;
2858 /*****
2859 * Get / Set Viewports
2860 *****/
2861 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 TRACE("(%p)\n", This);
2865 This->updateStateBlock->changed.viewport = TRUE;
2866 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2868 /* Handle recording of state blocks */
2869 if (This->isRecordingState) {
2870 TRACE("Recording... not performing anything\n");
2871 return WINED3D_OK;
2874 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2875 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2877 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2878 return WINED3D_OK;
2882 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p)\n", This);
2885 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2886 return WINED3D_OK;
2889 /*****
2890 * Get / Set Render States
2891 * TODO: Verify against dx9 definitions
2892 *****/
2893 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 DWORD oldValue = This->stateBlock->renderState[State];
2898 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2900 This->updateStateBlock->changed.renderState[State] = TRUE;
2901 This->updateStateBlock->renderState[State] = Value;
2903 /* Handle recording of state blocks */
2904 if (This->isRecordingState) {
2905 TRACE("Recording... not performing anything\n");
2906 return WINED3D_OK;
2909 /* Compared here and not before the assignment to allow proper stateblock recording */
2910 if(Value == oldValue) {
2911 TRACE("Application is setting the old value over, nothing to do\n");
2912 } else {
2913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2916 return WINED3D_OK;
2919 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2921 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2922 *pValue = This->stateBlock->renderState[State];
2923 return WINED3D_OK;
2926 /*****
2927 * Get / Set Sampler States
2928 * TODO: Verify against dx9 definitions
2929 *****/
2931 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2932 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2933 DWORD oldValue;
2935 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2936 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2938 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2939 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2943 * SetSampler is designed to allow for more than the standard up to 8 textures
2944 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2945 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2947 * http://developer.nvidia.com/object/General_FAQ.html#t6
2949 * There are two new settings for GForce
2950 * the sampler one:
2951 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2952 * and the texture one:
2953 * GL_MAX_TEXTURE_COORDS_ARB.
2954 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2955 ******************/
2957 oldValue = This->stateBlock->samplerState[Sampler][Type];
2958 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2959 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2961 /* Handle recording of state blocks */
2962 if (This->isRecordingState) {
2963 TRACE("Recording... not performing anything\n");
2964 return WINED3D_OK;
2967 if(oldValue == Value) {
2968 TRACE("Application is setting the old value over, nothing to do\n");
2969 return WINED3D_OK;
2972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2974 return WINED3D_OK;
2977 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2981 This, Sampler, debug_d3dsamplerstate(Type), Type);
2983 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2984 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2987 *Value = This->stateBlock->samplerState[Sampler][Type];
2988 TRACE("(%p) : Returning %#x\n", This, *Value);
2990 return WINED3D_OK;
2993 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2996 This->updateStateBlock->changed.scissorRect = TRUE;
2997 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2998 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2999 return WINED3D_OK;
3001 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3003 if(This->isRecordingState) {
3004 TRACE("Recording... not performing anything\n");
3005 return WINED3D_OK;
3008 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3010 return WINED3D_OK;
3013 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3017 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3018 return WINED3D_OK;
3021 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3023 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3025 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3027 This->updateStateBlock->vertexDecl = pDecl;
3028 This->updateStateBlock->changed.vertexDecl = TRUE;
3030 if (This->isRecordingState) {
3031 TRACE("Recording... not performing anything\n");
3032 return WINED3D_OK;
3033 } else if(pDecl == oldDecl) {
3034 /* Checked after the assignment to allow proper stateblock recording */
3035 TRACE("Application is setting the old declaration over, nothing to do\n");
3036 return WINED3D_OK;
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3040 return WINED3D_OK;
3043 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3048 *ppDecl = This->stateBlock->vertexDecl;
3049 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3050 return WINED3D_OK;
3053 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3057 This->updateStateBlock->vertexShader = pShader;
3058 This->updateStateBlock->changed.vertexShader = TRUE;
3060 if (This->isRecordingState) {
3061 TRACE("Recording... not performing anything\n");
3062 return WINED3D_OK;
3063 } else if(oldShader == pShader) {
3064 /* Checked here to allow proper stateblock recording */
3065 TRACE("App is setting the old shader over, nothing to do\n");
3066 return WINED3D_OK;
3069 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 if (NULL == ppShader) {
3080 return WINED3DERR_INVALIDCALL;
3082 *ppShader = This->stateBlock->vertexShader;
3083 if( NULL != *ppShader)
3084 IWineD3DVertexShader_AddRef(*ppShader);
3086 TRACE("(%p) : returning %p\n", This, *ppShader);
3087 return WINED3D_OK;
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3091 IWineD3DDevice *iface,
3092 UINT start,
3093 CONST BOOL *srcData,
3094 UINT count) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 int i, cnt = min(count, MAX_CONST_B - start);
3099 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3100 iface, srcData, start, count);
3102 if (srcData == NULL || cnt < 0)
3103 return WINED3DERR_INVALIDCALL;
3105 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3106 for (i = 0; i < cnt; i++)
3107 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3109 for (i = start; i < cnt + start; ++i) {
3110 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3113 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3115 return WINED3D_OK;
3118 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3119 IWineD3DDevice *iface,
3120 UINT start,
3121 BOOL *dstData,
3122 UINT count) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 int cnt = min(count, MAX_CONST_B - start);
3127 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3128 iface, dstData, start, count);
3130 if (dstData == NULL || cnt < 0)
3131 return WINED3DERR_INVALIDCALL;
3133 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3134 return WINED3D_OK;
3137 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3138 IWineD3DDevice *iface,
3139 UINT start,
3140 CONST int *srcData,
3141 UINT count) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 int i, cnt = min(count, MAX_CONST_I - start);
3146 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3147 iface, srcData, start, count);
3149 if (srcData == NULL || cnt < 0)
3150 return WINED3DERR_INVALIDCALL;
3152 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3153 for (i = 0; i < cnt; i++)
3154 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3155 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3157 for (i = start; i < cnt + start; ++i) {
3158 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3163 return WINED3D_OK;
3166 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3167 IWineD3DDevice *iface,
3168 UINT start,
3169 int *dstData,
3170 UINT count) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 int cnt = min(count, MAX_CONST_I - start);
3175 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3176 iface, dstData, start, count);
3178 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3179 return WINED3DERR_INVALIDCALL;
3181 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3182 return WINED3D_OK;
3185 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3186 IWineD3DDevice *iface,
3187 UINT start,
3188 CONST float *srcData,
3189 UINT count) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 int i;
3194 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3195 iface, srcData, start, count);
3197 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3198 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3199 return WINED3DERR_INVALIDCALL;
3201 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3202 if(TRACE_ON(d3d)) {
3203 for (i = 0; i < count; i++)
3204 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3205 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3208 for (i = start; i < count + start; ++i) {
3209 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3210 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3211 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3212 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3213 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3215 ptr->idx[ptr->count++] = i;
3216 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3222 return WINED3D_OK;
3225 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3226 IWineD3DDevice *iface,
3227 UINT start,
3228 float *dstData,
3229 UINT count) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3234 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3235 iface, dstData, start, count);
3237 if (dstData == NULL || cnt < 0)
3238 return WINED3DERR_INVALIDCALL;
3240 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3241 return WINED3D_OK;
3244 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3245 DWORD i;
3246 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3251 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3252 int i = This->rev_tex_unit_map[unit];
3253 int j = This->texUnitMap[stage];
3255 This->texUnitMap[stage] = unit;
3256 if (i != -1 && i != stage) {
3257 This->texUnitMap[i] = -1;
3260 This->rev_tex_unit_map[unit] = stage;
3261 if (j != -1 && j != unit) {
3262 This->rev_tex_unit_map[j] = -1;
3266 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3267 int i;
3269 for (i = 0; i < MAX_TEXTURES; ++i) {
3270 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3271 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3272 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3273 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3274 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3275 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3276 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3277 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3279 if (color_op == WINED3DTOP_DISABLE) {
3280 /* Not used, and disable higher stages */
3281 while (i < MAX_TEXTURES) {
3282 This->fixed_function_usage_map[i] = FALSE;
3283 ++i;
3285 break;
3288 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3289 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3290 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3291 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3292 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3293 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3294 This->fixed_function_usage_map[i] = TRUE;
3295 } else {
3296 This->fixed_function_usage_map[i] = FALSE;
3299 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3300 This->fixed_function_usage_map[i+1] = TRUE;
3305 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3306 int i, tex;
3308 device_update_fixed_function_usage_map(This);
3310 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3311 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3312 if (!This->fixed_function_usage_map[i]) continue;
3314 if (This->texUnitMap[i] != i) {
3315 device_map_stage(This, i, i);
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3317 markTextureStagesDirty(This, i);
3320 return;
3323 /* Now work out the mapping */
3324 tex = 0;
3325 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3326 if (!This->fixed_function_usage_map[i]) continue;
3328 if (This->texUnitMap[i] != tex) {
3329 device_map_stage(This, i, tex);
3330 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3331 markTextureStagesDirty(This, i);
3334 ++tex;
3338 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3339 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3340 int i;
3342 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3343 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3344 device_map_stage(This, i, i);
3345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3346 if (i < MAX_TEXTURES) {
3347 markTextureStagesDirty(This, i);
3353 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3354 int current_mapping = This->rev_tex_unit_map[unit];
3356 if (current_mapping == -1) {
3357 /* Not currently used */
3358 return TRUE;
3361 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3362 /* Used by a fragment sampler */
3364 if (!pshader_sampler_tokens) {
3365 /* No pixel shader, check fixed function */
3366 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3369 /* Pixel shader, check the shader's sampler map */
3370 return !pshader_sampler_tokens[current_mapping];
3373 /* Used by a vertex sampler */
3374 return !vshader_sampler_tokens[current_mapping];
3377 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3378 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3379 DWORD *pshader_sampler_tokens = NULL;
3380 int start = GL_LIMITS(combined_samplers) - 1;
3381 int i;
3383 if (ps) {
3384 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3386 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3387 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3388 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3391 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3392 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3393 if (vshader_sampler_tokens[i]) {
3394 if (This->texUnitMap[vsampler_idx] != -1) {
3395 /* Already mapped somewhere */
3396 continue;
3399 while (start >= 0) {
3400 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3401 device_map_stage(This, vsampler_idx, start);
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3404 --start;
3405 break;
3408 --start;
3414 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3415 BOOL vs = use_vs(This);
3416 BOOL ps = use_ps(This);
3418 * Rules are:
3419 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3420 * that would be really messy and require shader recompilation
3421 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3422 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3424 if (ps) {
3425 device_map_psamplers(This);
3426 } else {
3427 device_map_fixed_function_samplers(This);
3430 if (vs) {
3431 device_map_vsamplers(This, ps);
3435 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3438 This->updateStateBlock->pixelShader = pShader;
3439 This->updateStateBlock->changed.pixelShader = TRUE;
3441 /* Handle recording of state blocks */
3442 if (This->isRecordingState) {
3443 TRACE("Recording... not performing anything\n");
3446 if (This->isRecordingState) {
3447 TRACE("Recording... not performing anything\n");
3448 return WINED3D_OK;
3451 if(pShader == oldShader) {
3452 TRACE("App is setting the old pixel shader over, nothing to do\n");
3453 return WINED3D_OK;
3456 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3457 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3459 return WINED3D_OK;
3462 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3465 if (NULL == ppShader) {
3466 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3467 return WINED3DERR_INVALIDCALL;
3470 *ppShader = This->stateBlock->pixelShader;
3471 if (NULL != *ppShader) {
3472 IWineD3DPixelShader_AddRef(*ppShader);
3474 TRACE("(%p) : returning %p\n", This, *ppShader);
3475 return WINED3D_OK;
3478 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3479 IWineD3DDevice *iface,
3480 UINT start,
3481 CONST BOOL *srcData,
3482 UINT count) {
3484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3485 int i, cnt = min(count, MAX_CONST_B - start);
3487 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3488 iface, srcData, start, count);
3490 if (srcData == NULL || cnt < 0)
3491 return WINED3DERR_INVALIDCALL;
3493 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3494 for (i = 0; i < cnt; i++)
3495 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3497 for (i = start; i < cnt + start; ++i) {
3498 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3501 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3503 return WINED3D_OK;
3506 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3507 IWineD3DDevice *iface,
3508 UINT start,
3509 BOOL *dstData,
3510 UINT count) {
3512 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3513 int cnt = min(count, MAX_CONST_B - start);
3515 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3516 iface, dstData, start, count);
3518 if (dstData == NULL || cnt < 0)
3519 return WINED3DERR_INVALIDCALL;
3521 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3522 return WINED3D_OK;
3525 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3526 IWineD3DDevice *iface,
3527 UINT start,
3528 CONST int *srcData,
3529 UINT count) {
3531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3532 int i, cnt = min(count, MAX_CONST_I - start);
3534 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3535 iface, srcData, start, count);
3537 if (srcData == NULL || cnt < 0)
3538 return WINED3DERR_INVALIDCALL;
3540 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3541 for (i = 0; i < cnt; i++)
3542 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3543 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3545 for (i = start; i < cnt + start; ++i) {
3546 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3551 return WINED3D_OK;
3554 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3555 IWineD3DDevice *iface,
3556 UINT start,
3557 int *dstData,
3558 UINT count) {
3560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3561 int cnt = min(count, MAX_CONST_I - start);
3563 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3564 iface, dstData, start, count);
3566 if (dstData == NULL || cnt < 0)
3567 return WINED3DERR_INVALIDCALL;
3569 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3570 return WINED3D_OK;
3573 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3574 IWineD3DDevice *iface,
3575 UINT start,
3576 CONST float *srcData,
3577 UINT count) {
3579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3580 int i;
3582 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3583 iface, srcData, start, count);
3585 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3586 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3587 return WINED3DERR_INVALIDCALL;
3589 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3590 if(TRACE_ON(d3d)) {
3591 for (i = 0; i < count; i++)
3592 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3593 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3596 for (i = start; i < count + start; ++i) {
3597 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3598 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3599 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3600 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3601 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3603 ptr->idx[ptr->count++] = i;
3604 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3608 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3610 return WINED3D_OK;
3613 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3614 IWineD3DDevice *iface,
3615 UINT start,
3616 float *dstData,
3617 UINT count) {
3619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3620 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3622 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3623 iface, dstData, start, count);
3625 if (dstData == NULL || cnt < 0)
3626 return WINED3DERR_INVALIDCALL;
3628 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3629 return WINED3D_OK;
3632 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3633 static HRESULT
3634 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3635 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3636 unsigned int i;
3637 DWORD DestFVF = dest->fvf;
3638 WINED3DVIEWPORT vp;
3639 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3640 BOOL doClip;
3641 int numTextures;
3643 if (lpStrideData->u.s.normal.lpData) {
3644 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3647 if (lpStrideData->u.s.position.lpData == NULL) {
3648 ERR("Source has no position mask\n");
3649 return WINED3DERR_INVALIDCALL;
3652 /* We might access VBOs from this code, so hold the lock */
3653 ENTER_GL();
3655 if (dest->resource.allocatedMemory == NULL) {
3656 /* This may happen if we do direct locking into a vbo. Unlikely,
3657 * but theoretically possible(ddraw processvertices test)
3659 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3660 if(!dest->resource.allocatedMemory) {
3661 LEAVE_GL();
3662 ERR("Out of memory\n");
3663 return E_OUTOFMEMORY;
3665 if(dest->vbo) {
3666 void *src;
3667 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3668 checkGLcall("glBindBufferARB");
3669 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3670 if(src) {
3671 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3673 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3674 checkGLcall("glUnmapBufferARB");
3678 /* Get a pointer into the destination vbo(create one if none exists) and
3679 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3681 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3682 CreateVBO(dest);
3685 if(dest->vbo) {
3686 unsigned char extrabytes = 0;
3687 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3688 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3689 * this may write 4 extra bytes beyond the area that should be written
3691 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3692 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3693 if(!dest_conv_addr) {
3694 ERR("Out of memory\n");
3695 /* Continue without storing converted vertices */
3697 dest_conv = dest_conv_addr;
3700 /* Should I clip?
3701 * a) WINED3DRS_CLIPPING is enabled
3702 * b) WINED3DVOP_CLIP is passed
3704 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3705 static BOOL warned = FALSE;
3707 * The clipping code is not quite correct. Some things need
3708 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3709 * so disable clipping for now.
3710 * (The graphics in Half-Life are broken, and my processvertices
3711 * test crashes with IDirect3DDevice3)
3712 doClip = TRUE;
3714 doClip = FALSE;
3715 if(!warned) {
3716 warned = TRUE;
3717 FIXME("Clipping is broken and disabled for now\n");
3719 } else doClip = FALSE;
3720 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3722 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3723 WINED3DTS_VIEW,
3724 &view_mat);
3725 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3726 WINED3DTS_PROJECTION,
3727 &proj_mat);
3728 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3729 WINED3DTS_WORLDMATRIX(0),
3730 &world_mat);
3732 TRACE("View mat:\n");
3733 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);
3734 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);
3735 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);
3736 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);
3738 TRACE("Proj mat:\n");
3739 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);
3740 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);
3741 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);
3742 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);
3744 TRACE("World mat:\n");
3745 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);
3746 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);
3747 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);
3748 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);
3750 /* Get the viewport */
3751 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3752 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3753 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3755 multiply_matrix(&mat,&view_mat,&world_mat);
3756 multiply_matrix(&mat,&proj_mat,&mat);
3758 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3760 for (i = 0; i < dwCount; i+= 1) {
3761 unsigned int tex_index;
3763 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3764 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3765 /* The position first */
3766 float *p =
3767 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3768 float x, y, z, rhw;
3769 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3771 /* Multiplication with world, view and projection matrix */
3772 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);
3773 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);
3774 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);
3775 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);
3777 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3779 /* WARNING: The following things are taken from d3d7 and were not yet checked
3780 * against d3d8 or d3d9!
3783 /* Clipping conditions: From
3784 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3786 * A vertex is clipped if it does not match the following requirements
3787 * -rhw < x <= rhw
3788 * -rhw < y <= rhw
3789 * 0 < z <= rhw
3790 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3792 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3793 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3797 if( !doClip ||
3798 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3799 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3800 ( rhw > eps ) ) ) {
3802 /* "Normal" viewport transformation (not clipped)
3803 * 1) The values are divided by rhw
3804 * 2) The y axis is negative, so multiply it with -1
3805 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3806 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3807 * 4) Multiply x with Width/2 and add Width/2
3808 * 5) The same for the height
3809 * 6) Add the viewpoint X and Y to the 2D coordinates and
3810 * The minimum Z value to z
3811 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3813 * Well, basically it's simply a linear transformation into viewport
3814 * coordinates
3817 x /= rhw;
3818 y /= rhw;
3819 z /= rhw;
3821 y *= -1;
3823 x *= vp.Width / 2;
3824 y *= vp.Height / 2;
3825 z *= vp.MaxZ - vp.MinZ;
3827 x += vp.Width / 2 + vp.X;
3828 y += vp.Height / 2 + vp.Y;
3829 z += vp.MinZ;
3831 rhw = 1 / rhw;
3832 } else {
3833 /* That vertex got clipped
3834 * Contrary to OpenGL it is not dropped completely, it just
3835 * undergoes a different calculation.
3837 TRACE("Vertex got clipped\n");
3838 x += rhw;
3839 y += rhw;
3841 x /= 2;
3842 y /= 2;
3844 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3845 * outside of the main vertex buffer memory. That needs some more
3846 * investigation...
3850 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3853 ( (float *) dest_ptr)[0] = x;
3854 ( (float *) dest_ptr)[1] = y;
3855 ( (float *) dest_ptr)[2] = z;
3856 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3858 dest_ptr += 3 * sizeof(float);
3860 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3861 dest_ptr += sizeof(float);
3864 if(dest_conv) {
3865 float w = 1 / rhw;
3866 ( (float *) dest_conv)[0] = x * w;
3867 ( (float *) dest_conv)[1] = y * w;
3868 ( (float *) dest_conv)[2] = z * w;
3869 ( (float *) dest_conv)[3] = w;
3871 dest_conv += 3 * sizeof(float);
3873 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3874 dest_conv += sizeof(float);
3878 if (DestFVF & WINED3DFVF_PSIZE) {
3879 dest_ptr += sizeof(DWORD);
3880 if(dest_conv) dest_conv += sizeof(DWORD);
3882 if (DestFVF & WINED3DFVF_NORMAL) {
3883 float *normal =
3884 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3885 /* AFAIK this should go into the lighting information */
3886 FIXME("Didn't expect the destination to have a normal\n");
3887 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3888 if(dest_conv) {
3889 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3893 if (DestFVF & WINED3DFVF_DIFFUSE) {
3894 DWORD *color_d =
3895 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3896 if(!color_d) {
3897 static BOOL warned = FALSE;
3899 if(!warned) {
3900 ERR("No diffuse color in source, but destination has one\n");
3901 warned = TRUE;
3904 *( (DWORD *) dest_ptr) = 0xffffffff;
3905 dest_ptr += sizeof(DWORD);
3907 if(dest_conv) {
3908 *( (DWORD *) dest_conv) = 0xffffffff;
3909 dest_conv += sizeof(DWORD);
3912 else {
3913 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3914 if(dest_conv) {
3915 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3916 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3917 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3918 dest_conv += sizeof(DWORD);
3923 if (DestFVF & WINED3DFVF_SPECULAR) {
3924 /* What's the color value in the feedback buffer? */
3925 DWORD *color_s =
3926 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3927 if(!color_s) {
3928 static BOOL warned = FALSE;
3930 if(!warned) {
3931 ERR("No specular color in source, but destination has one\n");
3932 warned = TRUE;
3935 *( (DWORD *) dest_ptr) = 0xFF000000;
3936 dest_ptr += sizeof(DWORD);
3938 if(dest_conv) {
3939 *( (DWORD *) dest_conv) = 0xFF000000;
3940 dest_conv += sizeof(DWORD);
3943 else {
3944 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3945 if(dest_conv) {
3946 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3947 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3948 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3949 dest_conv += sizeof(DWORD);
3954 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3955 float *tex_coord =
3956 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3957 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3958 if(!tex_coord) {
3959 ERR("No source texture, but destination requests one\n");
3960 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3961 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3963 else {
3964 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3965 if(dest_conv) {
3966 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3972 if(dest_conv) {
3973 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3974 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3975 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3976 dwCount * get_flexible_vertex_size(DestFVF),
3977 dest_conv_addr));
3978 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3979 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3982 LEAVE_GL();
3984 return WINED3D_OK;
3986 #undef copy_and_next
3988 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3989 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3990 WineDirect3DVertexStridedData strided;
3991 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3992 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3994 if(pVertexDecl) {
3995 ERR("Output vertex declaration not implemented yet\n");
3998 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3999 * and this call is quite performance critical, so don't call needlessly
4001 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4002 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4005 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4006 * control the streamIsUP flag, thus restore it afterwards.
4008 This->stateBlock->streamIsUP = FALSE;
4009 memset(&strided, 0, sizeof(strided));
4010 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4011 This->stateBlock->streamIsUP = streamWasUP;
4013 if(vbo || SrcStartIndex) {
4014 unsigned int i;
4015 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4016 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4018 * Also get the start index in, but only loop over all elements if there's something to add at all.
4020 #define FIXSRC(type) \
4021 if(strided.u.s.type.VBO) { \
4022 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4023 strided.u.s.type.VBO = 0; \
4024 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4025 ENTER_GL(); \
4026 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4027 vb->vbo = 0; \
4028 LEAVE_GL(); \
4030 if(strided.u.s.type.lpData) { \
4031 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4033 FIXSRC(position);
4034 FIXSRC(blendWeights);
4035 FIXSRC(blendMatrixIndices);
4036 FIXSRC(normal);
4037 FIXSRC(pSize);
4038 FIXSRC(diffuse);
4039 FIXSRC(specular);
4040 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4041 FIXSRC(texCoords[i]);
4043 FIXSRC(position2);
4044 FIXSRC(normal2);
4045 FIXSRC(tangent);
4046 FIXSRC(binormal);
4047 FIXSRC(tessFactor);
4048 FIXSRC(fog);
4049 FIXSRC(depth);
4050 FIXSRC(sample);
4051 #undef FIXSRC
4054 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4057 /*****
4058 * Get / Set Texture Stage States
4059 * TODO: Verify against dx9 definitions
4060 *****/
4061 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4063 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4065 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4067 if (Stage >= MAX_TEXTURES) {
4068 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4069 return WINED3D_OK;
4072 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4073 This->updateStateBlock->textureState[Stage][Type] = Value;
4075 if (This->isRecordingState) {
4076 TRACE("Recording... not performing anything\n");
4077 return WINED3D_OK;
4080 /* Checked after the assignments to allow proper stateblock recording */
4081 if(oldValue == Value) {
4082 TRACE("App is setting the old value over, nothing to do\n");
4083 return WINED3D_OK;
4086 if(Stage > This->stateBlock->lowest_disabled_stage &&
4087 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4088 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4089 * Changes in other states are important on disabled stages too
4091 return WINED3D_OK;
4094 if(Type == WINED3DTSS_COLOROP) {
4095 int i;
4097 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4098 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4099 * they have to be disabled
4101 * The current stage is dirtified below.
4103 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4104 TRACE("Additionally dirtifying stage %d\n", i);
4105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4107 This->stateBlock->lowest_disabled_stage = Stage;
4108 TRACE("New lowest disabled: %d\n", Stage);
4109 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4110 /* Previously disabled stage enabled. Stages above it may need enabling
4111 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4112 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4114 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4117 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4118 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4119 break;
4121 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4124 This->stateBlock->lowest_disabled_stage = i;
4125 TRACE("New lowest disabled: %d\n", i);
4127 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4128 /* TODO: Built a stage -> texture unit mapping for register combiners */
4132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4134 return WINED3D_OK;
4137 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4139 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4140 *pValue = This->updateStateBlock->textureState[Stage][Type];
4141 return WINED3D_OK;
4144 /*****
4145 * Get / Set Texture
4146 *****/
4147 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4149 IWineD3DBaseTexture *oldTexture;
4151 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4153 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4154 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4157 oldTexture = This->updateStateBlock->textures[Stage];
4159 if(pTexture != NULL) {
4160 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4162 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4163 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4164 return WINED3DERR_INVALIDCALL;
4166 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4169 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4170 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4172 This->updateStateBlock->changed.textures[Stage] = TRUE;
4173 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4174 This->updateStateBlock->textures[Stage] = pTexture;
4176 /* Handle recording of state blocks */
4177 if (This->isRecordingState) {
4178 TRACE("Recording... not performing anything\n");
4179 return WINED3D_OK;
4182 if(oldTexture == pTexture) {
4183 TRACE("App is setting the same texture again, nothing to do\n");
4184 return WINED3D_OK;
4187 /** NOTE: MSDN says that setTexture increases the reference count,
4188 * and the the application must set the texture back to null (or have a leaky application),
4189 * This means we should pass the refcount up to the parent
4190 *******************************/
4191 if (NULL != This->updateStateBlock->textures[Stage]) {
4192 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4193 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4195 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4196 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4197 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4198 * so the COLOROP and ALPHAOP have to be dirtified.
4200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4203 if(bindCount == 1) {
4204 new->baseTexture.sampler = Stage;
4206 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4210 if (NULL != oldTexture) {
4211 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4212 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4214 IWineD3DBaseTexture_Release(oldTexture);
4215 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4220 if(bindCount && old->baseTexture.sampler == Stage) {
4221 int i;
4222 /* Have to do a search for the other sampler(s) where the texture is bound to
4223 * Shouldn't happen as long as apps bind a texture only to one stage
4225 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4226 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4227 if(This->updateStateBlock->textures[i] == oldTexture) {
4228 old->baseTexture.sampler = i;
4229 break;
4235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4237 return WINED3D_OK;
4240 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4243 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4245 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4246 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4249 *ppTexture=This->stateBlock->textures[Stage];
4250 if (*ppTexture)
4251 IWineD3DBaseTexture_AddRef(*ppTexture);
4253 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4255 return WINED3D_OK;
4258 /*****
4259 * Get Back Buffer
4260 *****/
4261 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4262 IWineD3DSurface **ppBackBuffer) {
4263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4264 IWineD3DSwapChain *swapChain;
4265 HRESULT hr;
4267 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4269 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4270 if (hr == WINED3D_OK) {
4271 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4272 IWineD3DSwapChain_Release(swapChain);
4273 } else {
4274 *ppBackBuffer = NULL;
4276 return hr;
4279 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4281 WARN("(%p) : stub, calling idirect3d for now\n", This);
4282 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4285 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4287 IWineD3DSwapChain *swapChain;
4288 HRESULT hr;
4290 if(iSwapChain > 0) {
4291 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4292 if (hr == WINED3D_OK) {
4293 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4294 IWineD3DSwapChain_Release(swapChain);
4295 } else {
4296 FIXME("(%p) Error getting display mode\n", This);
4298 } else {
4299 /* Don't read the real display mode,
4300 but return the stored mode instead. X11 can't change the color
4301 depth, and some apps are pretty angry if they SetDisplayMode from
4302 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4304 Also don't relay to the swapchain because with ddraw it's possible
4305 that there isn't a swapchain at all */
4306 pMode->Width = This->ddraw_width;
4307 pMode->Height = This->ddraw_height;
4308 pMode->Format = This->ddraw_format;
4309 pMode->RefreshRate = 0;
4310 hr = WINED3D_OK;
4313 return hr;
4316 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4318 TRACE("(%p)->(%p)\n", This, hWnd);
4320 if(This->ddraw_fullscreen) {
4321 if(This->ddraw_window && This->ddraw_window != hWnd) {
4322 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4324 if(hWnd && This->ddraw_window != hWnd) {
4325 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4329 This->ddraw_window = hWnd;
4330 return WINED3D_OK;
4333 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 TRACE("(%p)->(%p)\n", This, hWnd);
4337 *hWnd = This->ddraw_window;
4338 return WINED3D_OK;
4341 /*****
4342 * Stateblock related functions
4343 *****/
4345 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4347 IWineD3DStateBlockImpl *object;
4348 HRESULT temp_result;
4349 int i;
4351 TRACE("(%p)\n", This);
4353 if (This->isRecordingState) {
4354 return WINED3DERR_INVALIDCALL;
4357 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4358 if (NULL == object ) {
4359 FIXME("(%p)Error allocating memory for stateblock\n", This);
4360 return E_OUTOFMEMORY;
4362 TRACE("(%p) created object %p\n", This, object);
4363 object->wineD3DDevice= This;
4364 /** FIXME: object->parent = parent; **/
4365 object->parent = NULL;
4366 object->blockType = WINED3DSBT_RECORDED;
4367 object->ref = 1;
4368 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4370 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4371 list_init(&object->lightMap[i]);
4374 temp_result = allocate_shader_constants(object);
4375 if (WINED3D_OK != temp_result)
4376 return temp_result;
4378 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4379 This->updateStateBlock = object;
4380 This->isRecordingState = TRUE;
4382 TRACE("(%p) recording stateblock %p\n",This , object);
4383 return WINED3D_OK;
4386 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4388 unsigned int i, j;
4389 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4391 if (!This->isRecordingState) {
4392 FIXME("(%p) not recording! returning error\n", This);
4393 *ppStateBlock = NULL;
4394 return WINED3DERR_INVALIDCALL;
4397 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4398 if(object->changed.renderState[i]) {
4399 object->contained_render_states[object->num_contained_render_states] = i;
4400 object->num_contained_render_states++;
4403 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4404 if(object->changed.transform[i]) {
4405 object->contained_transform_states[object->num_contained_transform_states] = i;
4406 object->num_contained_transform_states++;
4409 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4410 if(object->changed.vertexShaderConstantsF[i]) {
4411 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4412 object->num_contained_vs_consts_f++;
4415 for(i = 0; i < MAX_CONST_I; i++) {
4416 if(object->changed.vertexShaderConstantsI[i]) {
4417 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4418 object->num_contained_vs_consts_i++;
4421 for(i = 0; i < MAX_CONST_B; i++) {
4422 if(object->changed.vertexShaderConstantsB[i]) {
4423 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4424 object->num_contained_vs_consts_b++;
4427 for(i = 0; i < MAX_CONST_I; i++) {
4428 if(object->changed.pixelShaderConstantsI[i]) {
4429 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4430 object->num_contained_ps_consts_i++;
4433 for(i = 0; i < MAX_CONST_B; i++) {
4434 if(object->changed.pixelShaderConstantsB[i]) {
4435 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4436 object->num_contained_ps_consts_b++;
4439 for(i = 0; i < MAX_TEXTURES; i++) {
4440 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4441 if(object->changed.textureState[i][j]) {
4442 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4443 object->contained_tss_states[object->num_contained_tss_states].state = j;
4444 object->num_contained_tss_states++;
4448 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4449 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4450 if(object->changed.samplerState[i][j]) {
4451 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4452 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4453 object->num_contained_sampler_states++;
4458 *ppStateBlock = (IWineD3DStateBlock*) object;
4459 This->isRecordingState = FALSE;
4460 This->updateStateBlock = This->stateBlock;
4461 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4462 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4463 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4464 return WINED3D_OK;
4467 /*****
4468 * Scene related functions
4469 *****/
4470 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4471 /* At the moment we have no need for any functionality at the beginning
4472 of a scene */
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4474 TRACE("(%p)\n", This);
4476 if(This->inScene) {
4477 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4478 return WINED3DERR_INVALIDCALL;
4480 This->inScene = TRUE;
4481 return WINED3D_OK;
4484 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 TRACE("(%p)\n", This);
4488 if(!This->inScene) {
4489 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4490 return WINED3DERR_INVALIDCALL;
4493 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4494 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4496 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4497 ENTER_GL();
4498 glFlush();
4499 checkGLcall("glFlush");
4500 LEAVE_GL();
4502 This->inScene = FALSE;
4503 return WINED3D_OK;
4506 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4507 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4508 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4510 IWineD3DSwapChain *swapChain = NULL;
4511 int i;
4512 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4514 TRACE("(%p) Presenting the frame\n", This);
4516 for(i = 0 ; i < swapchains ; i ++) {
4518 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4519 TRACE("presentinng chain %d, %p\n", i, swapChain);
4520 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4521 IWineD3DSwapChain_Release(swapChain);
4524 return WINED3D_OK;
4527 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4528 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4532 GLbitfield glMask = 0;
4533 unsigned int i;
4534 CONST WINED3DRECT* curRect;
4536 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4537 Count, pRects, Flags, Color, Z, Stencil);
4539 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4540 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4541 /* TODO: What about depth stencil buffers without stencil bits? */
4542 return WINED3DERR_INVALIDCALL;
4545 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4546 * and not the last active one.
4548 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4549 ENTER_GL();
4551 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4552 apply_fbo_state(iface);
4555 if (Count > 0 && pRects) {
4556 curRect = pRects;
4557 } else {
4558 curRect = NULL;
4561 /* Only set the values up once, as they are not changing */
4562 if (Flags & WINED3DCLEAR_STENCIL) {
4563 glClearStencil(Stencil);
4564 checkGLcall("glClearStencil");
4565 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4566 glStencilMask(0xFFFFFFFF);
4569 if (Flags & WINED3DCLEAR_ZBUFFER) {
4570 glDepthMask(GL_TRUE);
4571 glClearDepth(Z);
4572 checkGLcall("glClearDepth");
4573 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4577 if (Flags & WINED3DCLEAR_TARGET) {
4578 TRACE("Clearing screen with glClear to color %x\n", Color);
4579 glClearColor(D3DCOLOR_R(Color),
4580 D3DCOLOR_G(Color),
4581 D3DCOLOR_B(Color),
4582 D3DCOLOR_A(Color));
4583 checkGLcall("glClearColor");
4585 /* Clear ALL colors! */
4586 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4587 glMask = glMask | GL_COLOR_BUFFER_BIT;
4590 if (!curRect) {
4591 /* In drawable flag is set below */
4593 if (This->render_offscreen) {
4594 glScissor(This->stateBlock->viewport.X,
4595 This->stateBlock->viewport.Y,
4596 This->stateBlock->viewport.Width,
4597 This->stateBlock->viewport.Height);
4598 } else {
4599 glScissor(This->stateBlock->viewport.X,
4600 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4601 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4602 This->stateBlock->viewport.Width,
4603 This->stateBlock->viewport.Height);
4605 checkGLcall("glScissor");
4606 glClear(glMask);
4607 checkGLcall("glClear");
4608 } else {
4609 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4610 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4612 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4613 curRect[0].x2 < target->currentDesc.Width ||
4614 curRect[0].y2 < target->currentDesc.Height) {
4615 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4616 blt_to_drawable(This, target);
4620 /* Now process each rect in turn */
4621 for (i = 0; i < Count; i++) {
4622 /* Note gl uses lower left, width/height */
4623 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4624 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4625 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4626 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4628 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4629 * The rectangle is not cleared, no error is returned, but further rectanlges are
4630 * still cleared if they are valid
4632 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4633 TRACE("Rectangle with negative dimensions, ignoring\n");
4634 continue;
4637 if(This->render_offscreen) {
4638 glScissor(curRect[i].x1, curRect[i].y1,
4639 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4640 } else {
4641 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4642 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4644 checkGLcall("glScissor");
4646 glClear(glMask);
4647 checkGLcall("glClear");
4651 /* Restore the old values (why..?) */
4652 if (Flags & WINED3DCLEAR_STENCIL) {
4653 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4655 if (Flags & WINED3DCLEAR_TARGET) {
4656 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4657 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4658 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4659 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4660 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4663 LEAVE_GL();
4665 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4666 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4668 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4669 target->Flags |= SFLAG_INTEXTURE;
4670 target->Flags &= ~SFLAG_INSYSMEM;
4671 } else {
4672 target->Flags |= SFLAG_INDRAWABLE;
4673 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4675 return WINED3D_OK;
4678 /*****
4679 * Drawing functions
4680 *****/
4681 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4682 UINT PrimitiveCount) {
4684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4686 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4687 debug_d3dprimitivetype(PrimitiveType),
4688 StartVertex, PrimitiveCount);
4690 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4691 if(This->stateBlock->streamIsUP) {
4692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4693 This->stateBlock->streamIsUP = FALSE;
4696 if(This->stateBlock->loadBaseVertexIndex != 0) {
4697 This->stateBlock->loadBaseVertexIndex = 0;
4698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4700 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4701 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4702 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4703 return WINED3D_OK;
4706 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4707 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4708 WINED3DPRIMITIVETYPE PrimitiveType,
4709 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 UINT idxStride = 2;
4713 IWineD3DIndexBuffer *pIB;
4714 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4715 GLuint vbo;
4717 pIB = This->stateBlock->pIndexData;
4718 if (!pIB) {
4719 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4720 * without an index buffer set. (The first time at least...)
4721 * D3D8 simply dies, but I doubt it can do much harm to return
4722 * D3DERR_INVALIDCALL there as well. */
4723 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4724 return WINED3DERR_INVALIDCALL;
4727 if(This->stateBlock->streamIsUP) {
4728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4729 This->stateBlock->streamIsUP = FALSE;
4731 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4733 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4734 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4735 minIndex, NumVertices, startIndex, primCount);
4737 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4738 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4739 idxStride = 2;
4740 } else {
4741 idxStride = 4;
4744 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4745 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4746 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4749 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4750 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4752 return WINED3D_OK;
4755 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4756 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4757 UINT VertexStreamZeroStride) {
4758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4759 IWineD3DVertexBuffer *vb;
4761 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4762 debug_d3dprimitivetype(PrimitiveType),
4763 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4765 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4766 vb = This->stateBlock->streamSource[0];
4767 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4768 if(vb) IWineD3DVertexBuffer_Release(vb);
4769 This->stateBlock->streamOffset[0] = 0;
4770 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4771 This->stateBlock->streamIsUP = TRUE;
4772 This->stateBlock->loadBaseVertexIndex = 0;
4774 /* TODO: Only mark dirty if drawing from a different UP address */
4775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4777 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4778 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4780 /* MSDN specifies stream zero settings must be set to NULL */
4781 This->stateBlock->streamStride[0] = 0;
4782 This->stateBlock->streamSource[0] = NULL;
4784 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4785 * the new stream sources or use UP drawing again
4787 return WINED3D_OK;
4790 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4791 UINT MinVertexIndex, UINT NumVertices,
4792 UINT PrimitiveCount, CONST void* pIndexData,
4793 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4794 UINT VertexStreamZeroStride) {
4795 int idxStride;
4796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4797 IWineD3DVertexBuffer *vb;
4798 IWineD3DIndexBuffer *ib;
4800 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4801 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4802 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4803 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4805 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4806 idxStride = 2;
4807 } else {
4808 idxStride = 4;
4811 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4812 vb = This->stateBlock->streamSource[0];
4813 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4814 if(vb) IWineD3DVertexBuffer_Release(vb);
4815 This->stateBlock->streamIsUP = TRUE;
4816 This->stateBlock->streamOffset[0] = 0;
4817 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4819 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4820 This->stateBlock->baseVertexIndex = 0;
4821 This->stateBlock->loadBaseVertexIndex = 0;
4822 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4826 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4828 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4829 This->stateBlock->streamSource[0] = NULL;
4830 This->stateBlock->streamStride[0] = 0;
4831 ib = This->stateBlock->pIndexData;
4832 if(ib) {
4833 IWineD3DIndexBuffer_Release(ib);
4834 This->stateBlock->pIndexData = NULL;
4836 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4837 * SetStreamSource to specify a vertex buffer
4840 return WINED3D_OK;
4843 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4846 /* Mark the state dirty until we have nicer tracking
4847 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4848 * that value.
4850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4852 This->stateBlock->baseVertexIndex = 0;
4853 This->up_strided = DrawPrimStrideData;
4854 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4855 This->up_strided = NULL;
4856 return WINED3D_OK;
4859 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4860 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4861 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4863 /* Mark the state dirty until we have nicer tracking
4864 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4865 * that value.
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4869 This->stateBlock->streamIsUP = TRUE;
4870 This->stateBlock->baseVertexIndex = 0;
4871 This->up_strided = DrawPrimStrideData;
4872 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4873 This->up_strided = NULL;
4874 return WINED3D_OK;
4878 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4879 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4881 HRESULT hr = WINED3D_OK;
4882 WINED3DRESOURCETYPE sourceType;
4883 WINED3DRESOURCETYPE destinationType;
4884 int i ,levels;
4886 /* TODO: think about moving the code into IWineD3DBaseTexture */
4888 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4890 /* verify that the source and destination textures aren't NULL */
4891 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4892 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4893 This, pSourceTexture, pDestinationTexture);
4894 hr = WINED3DERR_INVALIDCALL;
4897 if (pSourceTexture == pDestinationTexture) {
4898 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4899 This, pSourceTexture, pDestinationTexture);
4900 hr = WINED3DERR_INVALIDCALL;
4902 /* Verify that the source and destination textures are the same type */
4903 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4904 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4906 if (sourceType != destinationType) {
4907 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4908 This);
4909 hr = WINED3DERR_INVALIDCALL;
4912 /* check that both textures have the identical numbers of levels */
4913 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4914 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4915 hr = WINED3DERR_INVALIDCALL;
4918 if (WINED3D_OK == hr) {
4920 /* Make sure that the destination texture is loaded */
4921 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4923 /* Update every surface level of the texture */
4924 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4926 switch (sourceType) {
4927 case WINED3DRTYPE_TEXTURE:
4929 IWineD3DSurface *srcSurface;
4930 IWineD3DSurface *destSurface;
4932 for (i = 0 ; i < levels ; ++i) {
4933 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4934 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4935 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4936 IWineD3DSurface_Release(srcSurface);
4937 IWineD3DSurface_Release(destSurface);
4938 if (WINED3D_OK != hr) {
4939 WARN("(%p) : Call to update surface failed\n", This);
4940 return hr;
4944 break;
4945 case WINED3DRTYPE_CUBETEXTURE:
4947 IWineD3DSurface *srcSurface;
4948 IWineD3DSurface *destSurface;
4949 WINED3DCUBEMAP_FACES faceType;
4951 for (i = 0 ; i < levels ; ++i) {
4952 /* Update each cube face */
4953 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4954 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4955 if (WINED3D_OK != hr) {
4956 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4957 } else {
4958 TRACE("Got srcSurface %p\n", srcSurface);
4960 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4961 if (WINED3D_OK != hr) {
4962 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4963 } else {
4964 TRACE("Got desrSurface %p\n", destSurface);
4966 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4967 IWineD3DSurface_Release(srcSurface);
4968 IWineD3DSurface_Release(destSurface);
4969 if (WINED3D_OK != hr) {
4970 WARN("(%p) : Call to update surface failed\n", This);
4971 return hr;
4976 break;
4977 #if 0 /* TODO: Add support for volume textures */
4978 case WINED3DRTYPE_VOLUMETEXTURE:
4980 IWineD3DVolume srcVolume = NULL;
4981 IWineD3DSurface destVolume = NULL;
4983 for (i = 0 ; i < levels ; ++i) {
4984 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4985 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4986 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4987 IWineD3DVolume_Release(srcSurface);
4988 IWineD3DVolume_Release(destSurface);
4989 if (WINED3D_OK != hr) {
4990 WARN("(%p) : Call to update volume failed\n", This);
4991 return hr;
4995 break;
4996 #endif
4997 default:
4998 FIXME("(%p) : Unsupported source and destination type\n", This);
4999 hr = WINED3DERR_INVALIDCALL;
5003 return hr;
5006 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5007 IWineD3DSwapChain *swapChain;
5008 HRESULT hr;
5009 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5010 if(hr == WINED3D_OK) {
5011 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5012 IWineD3DSwapChain_Release(swapChain);
5014 return hr;
5017 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5018 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5019 /* return a sensible default */
5020 *pNumPasses = 1;
5021 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5022 FIXME("(%p) : stub\n", This);
5023 return WINED3D_OK;
5026 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5027 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5028 int j;
5029 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5030 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5031 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5032 return WINED3DERR_INVALIDCALL;
5034 for (j = 0; j < 256; ++j) {
5035 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5036 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5037 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5038 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5040 TRACE("(%p) : returning\n", This);
5041 return WINED3D_OK;
5044 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5046 int j;
5047 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5048 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5049 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5050 return WINED3DERR_INVALIDCALL;
5052 for (j = 0; j < 256; ++j) {
5053 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5054 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5055 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5056 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5058 TRACE("(%p) : returning\n", This);
5059 return WINED3D_OK;
5062 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5064 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5065 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5066 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5067 return WINED3DERR_INVALIDCALL;
5069 /*TODO: stateblocks */
5070 This->currentPalette = PaletteNumber;
5071 TRACE("(%p) : returning\n", This);
5072 return WINED3D_OK;
5075 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5077 if (PaletteNumber == NULL) {
5078 WARN("(%p) : returning Invalid Call\n", This);
5079 return WINED3DERR_INVALIDCALL;
5081 /*TODO: stateblocks */
5082 *PaletteNumber = This->currentPalette;
5083 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5084 return WINED3D_OK;
5087 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5089 static BOOL showFixmes = TRUE;
5090 if (showFixmes) {
5091 FIXME("(%p) : stub\n", This);
5092 showFixmes = FALSE;
5095 This->softwareVertexProcessing = bSoftware;
5096 return WINED3D_OK;
5100 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 static BOOL showFixmes = TRUE;
5103 if (showFixmes) {
5104 FIXME("(%p) : stub\n", This);
5105 showFixmes = FALSE;
5107 return This->softwareVertexProcessing;
5111 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5113 IWineD3DSwapChain *swapChain;
5114 HRESULT hr;
5116 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5118 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5119 if(hr == WINED3D_OK){
5120 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5121 IWineD3DSwapChain_Release(swapChain);
5122 }else{
5123 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5125 return hr;
5129 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5131 static BOOL showfixmes = TRUE;
5132 if(nSegments != 0.0f) {
5133 if( showfixmes) {
5134 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5135 showfixmes = FALSE;
5138 return WINED3D_OK;
5141 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5143 static BOOL showfixmes = TRUE;
5144 if( showfixmes) {
5145 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5146 showfixmes = FALSE;
5148 return 0.0f;
5151 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5153 /** TODO: remove casts to IWineD3DSurfaceImpl
5154 * NOTE: move code to surface to accomplish this
5155 ****************************************/
5156 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5157 int srcWidth, srcHeight;
5158 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5159 WINED3DFORMAT destFormat, srcFormat;
5160 UINT destSize;
5161 int srcLeft, destLeft, destTop;
5162 WINED3DPOOL srcPool, destPool;
5163 int offset = 0;
5164 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5165 glDescriptor *glDescription = NULL;
5166 GLenum dummy;
5167 int bpp;
5168 CONVERT_TYPES convert = NO_CONVERSION;
5170 WINED3DSURFACE_DESC winedesc;
5172 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5173 memset(&winedesc, 0, sizeof(winedesc));
5174 winedesc.Width = &srcSurfaceWidth;
5175 winedesc.Height = &srcSurfaceHeight;
5176 winedesc.Pool = &srcPool;
5177 winedesc.Format = &srcFormat;
5179 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5181 winedesc.Width = &destSurfaceWidth;
5182 winedesc.Height = &destSurfaceHeight;
5183 winedesc.Pool = &destPool;
5184 winedesc.Format = &destFormat;
5185 winedesc.Size = &destSize;
5187 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5189 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5190 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5191 return WINED3DERR_INVALIDCALL;
5194 /* This call loads the opengl surface directly, instead of copying the surface to the
5195 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5196 * copy in sysmem and use regular surface loading.
5198 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5199 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5200 if(convert != NO_CONVERSION) {
5201 return IWineD3DSurface_BltFast(pDestinationSurface,
5202 pDestPoint ? pDestPoint->x : 0,
5203 pDestPoint ? pDestPoint->y : 0,
5204 pSourceSurface, (RECT *) pSourceRect, 0);
5207 if (destFormat == WINED3DFMT_UNKNOWN) {
5208 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5209 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5211 /* Get the update surface description */
5212 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5215 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5217 ENTER_GL();
5219 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5220 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5221 checkGLcall("glActiveTextureARB");
5224 /* Make sure the surface is loaded and up to date */
5225 IWineD3DSurface_PreLoad(pDestinationSurface);
5227 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5229 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5230 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5231 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5232 srcLeft = pSourceRect ? pSourceRect->left : 0;
5233 destLeft = pDestPoint ? pDestPoint->x : 0;
5234 destTop = pDestPoint ? pDestPoint->y : 0;
5237 /* This function doesn't support compressed textures
5238 the pitch is just bytesPerPixel * width */
5239 if(srcWidth != srcSurfaceWidth || srcLeft ){
5240 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5241 offset += srcLeft * pSrcSurface->bytesPerPixel;
5242 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5244 /* TODO DXT formats */
5246 if(pSourceRect != NULL && pSourceRect->top != 0){
5247 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5249 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5250 ,This
5251 ,glDescription->level
5252 ,destLeft
5253 ,destTop
5254 ,srcWidth
5255 ,srcHeight
5256 ,glDescription->glFormat
5257 ,glDescription->glType
5258 ,IWineD3DSurface_GetData(pSourceSurface)
5261 /* Sanity check */
5262 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5264 /* need to lock the surface to get the data */
5265 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5268 /* TODO: Cube and volume support */
5269 if(rowoffset != 0){
5270 /* not a whole row so we have to do it a line at a time */
5271 int j;
5273 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5274 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5276 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5278 glTexSubImage2D(glDescription->target
5279 ,glDescription->level
5280 ,destLeft
5282 ,srcWidth
5284 ,glDescription->glFormat
5285 ,glDescription->glType
5286 ,data /* could be quicker using */
5288 data += rowoffset;
5291 } else { /* Full width, so just write out the whole texture */
5293 if (WINED3DFMT_DXT1 == destFormat ||
5294 WINED3DFMT_DXT2 == destFormat ||
5295 WINED3DFMT_DXT3 == destFormat ||
5296 WINED3DFMT_DXT4 == destFormat ||
5297 WINED3DFMT_DXT5 == destFormat) {
5298 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5299 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5300 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5301 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5302 } if (destFormat != srcFormat) {
5303 FIXME("Updating mixed format compressed texture is not curretly support\n");
5304 } else {
5305 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5306 glDescription->level,
5307 glDescription->glFormatInternal,
5308 srcWidth,
5309 srcHeight,
5311 destSize,
5312 IWineD3DSurface_GetData(pSourceSurface));
5314 } else {
5315 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5319 } else {
5320 glTexSubImage2D(glDescription->target
5321 ,glDescription->level
5322 ,destLeft
5323 ,destTop
5324 ,srcWidth
5325 ,srcHeight
5326 ,glDescription->glFormat
5327 ,glDescription->glType
5328 ,IWineD3DSurface_GetData(pSourceSurface)
5332 checkGLcall("glTexSubImage2D");
5334 LEAVE_GL();
5336 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5337 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5340 return WINED3D_OK;
5343 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5345 struct WineD3DRectPatch *patch;
5346 unsigned int i;
5347 struct list *e;
5348 BOOL found;
5349 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5351 if(!(Handle || pRectPatchInfo)) {
5352 /* TODO: Write a test for the return value, thus the FIXME */
5353 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5354 return WINED3DERR_INVALIDCALL;
5357 if(Handle) {
5358 i = PATCHMAP_HASHFUNC(Handle);
5359 found = FALSE;
5360 LIST_FOR_EACH(e, &This->patches[i]) {
5361 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5362 if(patch->Handle == Handle) {
5363 found = TRUE;
5364 break;
5368 if(!found) {
5369 TRACE("Patch does not exist. Creating a new one\n");
5370 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5371 patch->Handle = Handle;
5372 list_add_head(&This->patches[i], &patch->entry);
5373 } else {
5374 TRACE("Found existing patch %p\n", patch);
5376 } else {
5377 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5378 * attributes we have to tesselate, read back, and draw. This needs a patch
5379 * management structure instance. Create one.
5381 * A possible improvement is to check if a vertex shader is used, and if not directly
5382 * draw the patch.
5384 FIXME("Drawing an uncached patch. This is slow\n");
5385 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5388 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5389 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5390 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5391 HRESULT hr;
5392 TRACE("Tesselation density or patch info changed, retesselating\n");
5394 if(pRectPatchInfo) {
5395 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5397 patch->numSegs[0] = pNumSegs[0];
5398 patch->numSegs[1] = pNumSegs[1];
5399 patch->numSegs[2] = pNumSegs[2];
5400 patch->numSegs[3] = pNumSegs[3];
5402 hr = tesselate_rectpatch(This, patch);
5403 if(FAILED(hr)) {
5404 WARN("Patch tesselation failed\n");
5406 /* Do not release the handle to store the params of the patch */
5407 if(!Handle) {
5408 HeapFree(GetProcessHeap(), 0, patch);
5410 return hr;
5414 This->currentPatch = patch;
5415 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5416 This->currentPatch = NULL;
5418 /* Destroy uncached patches */
5419 if(!Handle) {
5420 HeapFree(GetProcessHeap(), 0, patch->mem);
5421 HeapFree(GetProcessHeap(), 0, patch);
5423 return WINED3D_OK;
5426 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5427 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5429 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5430 FIXME("(%p) : Stub\n", This);
5431 return WINED3D_OK;
5434 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5436 int i;
5437 struct WineD3DRectPatch *patch;
5438 struct list *e;
5439 TRACE("(%p) Handle(%d)\n", This, Handle);
5441 i = PATCHMAP_HASHFUNC(Handle);
5442 LIST_FOR_EACH(e, &This->patches[i]) {
5443 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5444 if(patch->Handle == Handle) {
5445 TRACE("Deleting patch %p\n", patch);
5446 list_remove(&patch->entry);
5447 HeapFree(GetProcessHeap(), 0, patch->mem);
5448 HeapFree(GetProcessHeap(), 0, patch);
5449 return WINED3D_OK;
5453 /* TODO: Write a test for the return value */
5454 FIXME("Attempt to destroy nonexistant patch\n");
5455 return WINED3DERR_INVALIDCALL;
5458 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5459 HRESULT hr;
5460 IWineD3DSwapChain *swapchain;
5462 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5463 if (SUCCEEDED(hr)) {
5464 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5465 return swapchain;
5468 return NULL;
5471 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5474 if (!*fbo) {
5475 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5476 checkGLcall("glGenFramebuffersEXT()");
5478 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5479 checkGLcall("glBindFramebuffer()");
5482 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5483 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5484 IWineD3DBaseTextureImpl *texture_impl;
5485 GLenum texttarget, target;
5486 GLint old_binding;
5488 texttarget = surface_impl->glDescription.target;
5489 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5490 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5492 IWineD3DSurface_PreLoad(surface);
5494 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5495 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5496 glBindTexture(target, old_binding);
5498 /* Update base texture states array */
5499 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5500 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5501 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5502 if (texture_impl->baseTexture.bindCount) {
5503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5506 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5509 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5510 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5512 checkGLcall("attach_surface_fbo");
5515 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5517 IWineD3DSwapChain *swapchain;
5519 swapchain = get_swapchain(surface);
5520 if (swapchain) {
5521 GLenum buffer;
5523 TRACE("Surface %p is onscreen\n", surface);
5525 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5526 buffer = surface_get_gl_buffer(surface, swapchain);
5527 glDrawBuffer(buffer);
5528 checkGLcall("glDrawBuffer()");
5529 } else {
5530 TRACE("Surface %p is offscreen\n", surface);
5531 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5532 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5535 if (rect) {
5536 glEnable(GL_SCISSOR_TEST);
5537 if(!swapchain) {
5538 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5539 } else {
5540 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5541 rect->x2 - rect->x1, rect->y2 - rect->y1);
5543 checkGLcall("glScissor");
5544 } else {
5545 glDisable(GL_SCISSOR_TEST);
5547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5549 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5552 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5553 glClear(GL_COLOR_BUFFER_BIT);
5554 checkGLcall("glClear");
5556 if (This->render_offscreen) {
5557 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5558 } else {
5559 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5560 checkGLcall("glBindFramebuffer()");
5563 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5564 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5565 glDrawBuffer(GL_BACK);
5566 checkGLcall("glDrawBuffer()");
5570 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5572 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5573 WINEDDBLTFX BltFx;
5574 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5576 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5577 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5578 return WINED3DERR_INVALIDCALL;
5581 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5582 color_fill_fbo(iface, pSurface, pRect, color);
5583 return WINED3D_OK;
5584 } else {
5585 /* Just forward this to the DirectDraw blitting engine */
5586 memset(&BltFx, 0, sizeof(BltFx));
5587 BltFx.dwSize = sizeof(BltFx);
5588 BltFx.u5.dwFillColor = color;
5589 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5593 /* rendertarget and deptth stencil functions */
5594 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5597 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5598 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5599 return WINED3DERR_INVALIDCALL;
5602 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5603 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5604 /* Note inc ref on returned surface */
5605 if(*ppRenderTarget != NULL)
5606 IWineD3DSurface_AddRef(*ppRenderTarget);
5607 return WINED3D_OK;
5610 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5613 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5614 IWineD3DSwapChainImpl *Swapchain;
5615 HRESULT hr;
5617 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5619 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5620 if(hr != WINED3D_OK) {
5621 ERR("Can't get the swapchain\n");
5622 return hr;
5625 /* Make sure to release the swapchain */
5626 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5628 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5629 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5630 return WINED3DERR_INVALIDCALL;
5632 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5633 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5634 return WINED3DERR_INVALIDCALL;
5637 if(Swapchain->frontBuffer != Front) {
5638 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5640 if(Swapchain->frontBuffer)
5641 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5642 Swapchain->frontBuffer = Front;
5644 if(Swapchain->frontBuffer) {
5645 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5649 if(Back && !Swapchain->backBuffer) {
5650 /* We need memory for the back buffer array - only one back buffer this way */
5651 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5652 if(!Swapchain->backBuffer) {
5653 ERR("Out of memory\n");
5654 return E_OUTOFMEMORY;
5658 if(Swapchain->backBuffer[0] != Back) {
5659 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5661 /* What to do about the context here in the case of multithreading? Not sure.
5662 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5664 ENTER_GL();
5665 if(!Swapchain->backBuffer[0]) {
5666 /* GL was told to draw to the front buffer at creation,
5667 * undo that
5669 glDrawBuffer(GL_BACK);
5670 checkGLcall("glDrawBuffer(GL_BACK)");
5671 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5672 Swapchain->presentParms.BackBufferCount = 1;
5673 } else if (!Back) {
5674 /* That makes problems - disable for now */
5675 /* glDrawBuffer(GL_FRONT); */
5676 checkGLcall("glDrawBuffer(GL_FRONT)");
5677 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5678 Swapchain->presentParms.BackBufferCount = 0;
5680 LEAVE_GL();
5682 if(Swapchain->backBuffer[0])
5683 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5684 Swapchain->backBuffer[0] = Back;
5686 if(Swapchain->backBuffer[0]) {
5687 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5688 } else {
5689 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5694 return WINED3D_OK;
5697 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5699 *ppZStencilSurface = This->depthStencilBuffer;
5700 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5702 if(*ppZStencilSurface != NULL) {
5703 /* Note inc ref on returned surface */
5704 IWineD3DSurface_AddRef(*ppZStencilSurface);
5706 return WINED3D_OK;
5709 /* TODO: Handle stencil attachments */
5710 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5714 TRACE("Set depth stencil to %p\n", depth_stencil);
5716 if (depth_stencil_impl) {
5717 if (depth_stencil_impl->current_renderbuffer) {
5718 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5719 checkGLcall("glFramebufferRenderbufferEXT()");
5720 } else {
5721 IWineD3DBaseTextureImpl *texture_impl;
5722 GLenum texttarget, target;
5723 GLint old_binding = 0;
5725 texttarget = depth_stencil_impl->glDescription.target;
5726 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5727 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5729 IWineD3DSurface_PreLoad(depth_stencil);
5731 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5732 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5733 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5734 glBindTexture(target, old_binding);
5736 /* Update base texture states array */
5737 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5738 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5739 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5740 if (texture_impl->baseTexture.bindCount) {
5741 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5744 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5747 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5748 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5749 checkGLcall("glFramebufferTexture2DEXT()");
5751 } else {
5752 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5753 checkGLcall("glFramebufferTexture2DEXT()");
5757 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5759 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5761 TRACE("Set render target %u to %p\n", idx, render_target);
5763 if (rtimpl) {
5764 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5765 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5766 } else {
5767 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5768 checkGLcall("glFramebufferTexture2DEXT()");
5770 This->draw_buffers[idx] = GL_NONE;
5774 static void check_fbo_status(IWineD3DDevice *iface) {
5775 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5776 GLenum status;
5778 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5779 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5780 TRACE("FBO complete\n");
5781 } else {
5782 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5784 /* Dump the FBO attachments */
5785 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5786 IWineD3DSurfaceImpl *attachment;
5787 int i;
5789 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5790 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5791 if (attachment) {
5792 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5793 attachment->pow2Width, attachment->pow2Height);
5796 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5797 if (attachment) {
5798 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5799 attachment->pow2Width, attachment->pow2Height);
5805 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5807 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5808 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5810 if (!ds_impl) return FALSE;
5812 if (ds_impl->current_renderbuffer) {
5813 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5814 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5817 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5818 rt_impl->pow2Height != ds_impl->pow2Height);
5821 void apply_fbo_state(IWineD3DDevice *iface) {
5822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5823 unsigned int i;
5825 if (This->render_offscreen) {
5826 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5828 /* Apply render targets */
5829 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5830 IWineD3DSurface *render_target = This->render_targets[i];
5831 if (This->fbo_color_attachments[i] != render_target) {
5832 set_render_target_fbo(iface, i, render_target);
5833 This->fbo_color_attachments[i] = render_target;
5837 /* Apply depth targets */
5838 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5839 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5840 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5842 if (This->stencilBufferTarget) {
5843 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5845 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5846 This->fbo_depth_attachment = This->stencilBufferTarget;
5849 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5850 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5851 checkGLcall("glDrawBuffers()");
5852 } else {
5853 glDrawBuffer(This->draw_buffers[0]);
5854 checkGLcall("glDrawBuffer()");
5856 } else {
5857 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5860 check_fbo_status(iface);
5863 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5864 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5865 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5866 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5867 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5868 GLenum gl_filter;
5870 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5871 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5872 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5873 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5875 switch (filter) {
5876 case WINED3DTEXF_LINEAR:
5877 gl_filter = GL_LINEAR;
5878 break;
5880 default:
5881 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5882 case WINED3DTEXF_NONE:
5883 case WINED3DTEXF_POINT:
5884 gl_filter = GL_NEAREST;
5885 break;
5888 /* Attach src surface to src fbo */
5889 src_swapchain = get_swapchain(src_surface);
5890 if (src_swapchain) {
5891 GLenum buffer;
5893 TRACE("Source surface %p is onscreen\n", src_surface);
5894 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5896 ENTER_GL();
5897 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5898 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5899 glReadBuffer(buffer);
5900 checkGLcall("glReadBuffer()");
5902 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5903 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5904 } else {
5905 TRACE("Source surface %p is offscreen\n", src_surface);
5906 ENTER_GL();
5907 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5908 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5909 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5910 checkGLcall("glReadBuffer()");
5912 LEAVE_GL();
5914 /* Attach dst surface to dst fbo */
5915 dst_swapchain = get_swapchain(dst_surface);
5916 if (dst_swapchain) {
5917 GLenum buffer;
5919 TRACE("Destination surface %p is onscreen\n", dst_surface);
5920 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5922 ENTER_GL();
5923 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5924 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5925 glDrawBuffer(buffer);
5926 checkGLcall("glDrawBuffer()");
5928 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5929 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5930 } else {
5931 TRACE("Destination surface %p is offscreen\n", dst_surface);
5933 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5934 if(!src_swapchain) {
5935 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5938 ENTER_GL();
5939 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5940 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5941 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5942 checkGLcall("glDrawBuffer()");
5944 glDisable(GL_SCISSOR_TEST);
5945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5947 if (flip) {
5948 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5949 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5950 checkGLcall("glBlitFramebuffer()");
5951 } else {
5952 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5953 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5954 checkGLcall("glBlitFramebuffer()");
5957 if (This->render_offscreen) {
5958 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5959 } else {
5960 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5961 checkGLcall("glBindFramebuffer()");
5964 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5965 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5966 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5967 glDrawBuffer(GL_BACK);
5968 checkGLcall("glDrawBuffer()");
5970 LEAVE_GL();
5973 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5974 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5975 WINED3DVIEWPORT viewport;
5977 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5979 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5980 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5981 return WINED3DERR_INVALIDCALL;
5984 /* MSDN says that null disables the render target
5985 but a device must always be associated with a render target
5986 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5988 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5989 for more details
5991 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5992 FIXME("Trying to set render target 0 to NULL\n");
5993 return WINED3DERR_INVALIDCALL;
5995 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5996 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);
5997 return WINED3DERR_INVALIDCALL;
6000 /* If we are trying to set what we already have, don't bother */
6001 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6002 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6003 return WINED3D_OK;
6005 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6006 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6007 This->render_targets[RenderTargetIndex] = pRenderTarget;
6009 /* Render target 0 is special */
6010 if(RenderTargetIndex == 0) {
6011 /* Finally, reset the viewport as the MSDN states. */
6012 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6013 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6014 viewport.X = 0;
6015 viewport.Y = 0;
6016 viewport.MaxZ = 1.0f;
6017 viewport.MinZ = 0.0f;
6018 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6019 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6020 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6022 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6024 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6025 * ctx properly.
6026 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6027 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6029 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6031 return WINED3D_OK;
6034 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6036 HRESULT hr = WINED3D_OK;
6037 IWineD3DSurface *tmp;
6039 TRACE("(%p) Swapping z-buffer\n",This);
6041 if (pNewZStencil == This->stencilBufferTarget) {
6042 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6043 } else {
6044 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6045 * depending on the renter target implementation being used.
6046 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6047 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6048 * stencil buffer and incure an extra memory overhead
6049 ******************************************************/
6051 tmp = This->stencilBufferTarget;
6052 This->stencilBufferTarget = pNewZStencil;
6053 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6054 /* should we be calling the parent or the wined3d surface? */
6055 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6056 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6057 hr = WINED3D_OK;
6059 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6060 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6067 return hr;
6070 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6071 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6073 /* TODO: the use of Impl is deprecated. */
6074 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6075 WINED3DLOCKED_RECT lockedRect;
6077 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6079 /* some basic validation checks */
6080 if(This->cursorTexture) {
6081 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6082 ENTER_GL();
6083 glDeleteTextures(1, &This->cursorTexture);
6084 LEAVE_GL();
6085 This->cursorTexture = 0;
6088 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6089 This->haveHardwareCursor = TRUE;
6090 else
6091 This->haveHardwareCursor = FALSE;
6093 if(pCursorBitmap) {
6094 WINED3DLOCKED_RECT rect;
6096 /* MSDN: Cursor must be A8R8G8B8 */
6097 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6098 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6099 return WINED3DERR_INVALIDCALL;
6102 /* MSDN: Cursor must be smaller than the display mode */
6103 if(pSur->currentDesc.Width > This->ddraw_width ||
6104 pSur->currentDesc.Height > This->ddraw_height) {
6105 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);
6106 return WINED3DERR_INVALIDCALL;
6109 if (!This->haveHardwareCursor) {
6110 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6112 /* Do not store the surface's pointer because the application may
6113 * release it after setting the cursor image. Windows doesn't
6114 * addref the set surface, so we can't do this either without
6115 * creating circular refcount dependencies. Copy out the gl texture
6116 * instead.
6118 This->cursorWidth = pSur->currentDesc.Width;
6119 This->cursorHeight = pSur->currentDesc.Height;
6120 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6122 const GlPixelFormatDesc *glDesc;
6123 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6124 char *mem, *bits = (char *)rect.pBits;
6125 GLint intfmt = glDesc->glInternal;
6126 GLint format = glDesc->glFormat;
6127 GLint type = glDesc->glType;
6128 INT height = This->cursorHeight;
6129 INT width = This->cursorWidth;
6130 INT bpp = tableEntry->bpp;
6131 INT i;
6133 /* Reformat the texture memory (pitch and width can be
6134 * different) */
6135 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6136 for(i = 0; i < height; i++)
6137 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6138 IWineD3DSurface_UnlockRect(pCursorBitmap);
6139 ENTER_GL();
6141 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6142 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6143 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6146 /* Make sure that a proper texture unit is selected */
6147 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6148 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6149 checkGLcall("glActiveTextureARB");
6151 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6152 /* Create a new cursor texture */
6153 glGenTextures(1, &This->cursorTexture);
6154 checkGLcall("glGenTextures");
6155 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6156 checkGLcall("glBindTexture");
6157 /* Copy the bitmap memory into the cursor texture */
6158 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6159 HeapFree(GetProcessHeap(), 0, mem);
6160 checkGLcall("glTexImage2D");
6162 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6163 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6164 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6167 LEAVE_GL();
6169 else
6171 FIXME("A cursor texture was not returned.\n");
6172 This->cursorTexture = 0;
6175 else
6177 /* Draw a hardware cursor */
6178 ICONINFO cursorInfo;
6179 HCURSOR cursor;
6180 /* Create and clear maskBits because it is not needed for
6181 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6182 * chunks. */
6183 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6184 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6185 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6186 WINED3DLOCK_NO_DIRTY_UPDATE |
6187 WINED3DLOCK_READONLY
6189 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6190 pSur->currentDesc.Height);
6192 cursorInfo.fIcon = FALSE;
6193 cursorInfo.xHotspot = XHotSpot;
6194 cursorInfo.yHotspot = YHotSpot;
6195 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6196 pSur->currentDesc.Height, 1,
6197 1, &maskBits);
6198 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6199 pSur->currentDesc.Height, 1,
6200 32, lockedRect.pBits);
6201 IWineD3DSurface_UnlockRect(pCursorBitmap);
6202 /* Create our cursor and clean up. */
6203 cursor = CreateIconIndirect(&cursorInfo);
6204 SetCursor(cursor);
6205 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6206 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6207 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6208 This->hardwareCursor = cursor;
6209 HeapFree(GetProcessHeap(), 0, maskBits);
6213 This->xHotSpot = XHotSpot;
6214 This->yHotSpot = YHotSpot;
6215 return WINED3D_OK;
6218 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6220 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6222 This->xScreenSpace = XScreenSpace;
6223 This->yScreenSpace = YScreenSpace;
6225 return;
6229 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6231 BOOL oldVisible = This->bCursorVisible;
6232 POINT pt;
6234 TRACE("(%p) : visible(%d)\n", This, bShow);
6237 * When ShowCursor is first called it should make the cursor appear at the OS's last
6238 * known cursor position. Because of this, some applications just repetitively call
6239 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6241 GetCursorPos(&pt);
6242 This->xScreenSpace = pt.x;
6243 This->yScreenSpace = pt.y;
6245 if (This->haveHardwareCursor) {
6246 This->bCursorVisible = bShow;
6247 if (bShow)
6248 SetCursor(This->hardwareCursor);
6249 else
6250 SetCursor(NULL);
6252 else
6254 if (This->cursorTexture)
6255 This->bCursorVisible = bShow;
6258 return oldVisible;
6261 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6263 TRACE("(%p) : state (%u)\n", This, This->state);
6264 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6265 switch (This->state) {
6266 case WINED3D_OK:
6267 return WINED3D_OK;
6268 case WINED3DERR_DEVICELOST:
6270 ResourceList *resourceList = This->resources;
6271 while (NULL != resourceList) {
6272 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6273 return WINED3DERR_DEVICENOTRESET;
6274 resourceList = resourceList->next;
6276 return WINED3DERR_DEVICELOST;
6278 case WINED3DERR_DRIVERINTERNALERROR:
6279 return WINED3DERR_DRIVERINTERNALERROR;
6282 /* Unknown state */
6283 return WINED3DERR_DRIVERINTERNALERROR;
6287 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6289 /** FIXME: Resource tracking needs to be done,
6290 * The closes we can do to this is set the priorities of all managed textures low
6291 * and then reset them.
6292 ***********************************************************/
6293 FIXME("(%p) : stub\n", This);
6294 return WINED3D_OK;
6297 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6298 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6300 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6301 if(surface->Flags & SFLAG_DIBSECTION) {
6302 /* Release the DC */
6303 SelectObject(surface->hDC, surface->dib.holdbitmap);
6304 DeleteDC(surface->hDC);
6305 /* Release the DIB section */
6306 DeleteObject(surface->dib.DIBsection);
6307 surface->dib.bitmap_data = NULL;
6308 surface->resource.allocatedMemory = NULL;
6309 surface->Flags &= ~SFLAG_DIBSECTION;
6311 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6312 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6313 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6314 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6315 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6316 } else {
6317 surface->pow2Width = surface->pow2Height = 1;
6318 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6319 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6321 if(surface->glDescription.textureName) {
6322 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6323 ENTER_GL();
6324 glDeleteTextures(1, &surface->glDescription.textureName);
6325 LEAVE_GL();
6326 surface->glDescription.textureName = 0;
6327 surface->Flags &= ~SFLAG_CLIENT;
6329 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6330 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6331 surface->Flags |= SFLAG_NONPOW2;
6332 } else {
6333 surface->Flags &= ~SFLAG_NONPOW2;
6335 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6336 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6339 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6341 IWineD3DSwapChainImpl *swapchain;
6342 HRESULT hr;
6343 BOOL DisplayModeChanged = FALSE;
6344 WINED3DDISPLAYMODE mode;
6345 TRACE("(%p)\n", This);
6347 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6348 if(FAILED(hr)) {
6349 ERR("Failed to get the first implicit swapchain\n");
6350 return hr;
6353 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6354 * on an existing gl context, so there's no real need for recreation.
6356 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6358 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6360 TRACE("New params:\n");
6361 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6362 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6363 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6364 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6365 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6366 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6367 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6368 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6369 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6370 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6371 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6372 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6373 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6375 /* No special treatment of these parameters. Just store them */
6376 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6377 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6378 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6379 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6381 /* What to do about these? */
6382 if(pPresentationParameters->BackBufferCount != 0 &&
6383 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6384 ERR("Cannot change the back buffer count yet\n");
6386 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6387 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6388 ERR("Cannot change the back buffer format yet\n");
6390 if(pPresentationParameters->hDeviceWindow != NULL &&
6391 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6392 ERR("Cannot change the device window yet\n");
6394 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6395 ERR("What do do about a changed auto depth stencil parameter?\n");
6398 if(pPresentationParameters->Windowed) {
6399 mode.Width = swapchain->orig_width;
6400 mode.Height = swapchain->orig_height;
6401 mode.RefreshRate = 0;
6402 mode.Format = swapchain->presentParms.BackBufferFormat;
6403 } else {
6404 mode.Width = pPresentationParameters->BackBufferWidth;
6405 mode.Height = pPresentationParameters->BackBufferHeight;
6406 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6407 mode.Format = swapchain->presentParms.BackBufferFormat;
6410 /* Should Width == 800 && Height == 0 set 800x600? */
6411 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6412 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6413 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6415 WINED3DVIEWPORT vp;
6416 int i;
6418 vp.X = 0;
6419 vp.Y = 0;
6420 vp.Width = pPresentationParameters->BackBufferWidth;
6421 vp.Height = pPresentationParameters->BackBufferHeight;
6422 vp.MinZ = 0;
6423 vp.MaxZ = 1;
6425 if(!pPresentationParameters->Windowed) {
6426 DisplayModeChanged = TRUE;
6428 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6429 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6431 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6432 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6433 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6436 /* Now set the new viewport */
6437 IWineD3DDevice_SetViewport(iface, &vp);
6440 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6441 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6442 DisplayModeChanged) {
6444 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6445 if(!pPresentationParameters->Windowed) {
6446 IWineD3DDevice_SetFullscreen(iface, TRUE);
6449 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6451 /* Switching out of fullscreen mode? First set the original res, then change the window */
6452 if(pPresentationParameters->Windowed) {
6453 IWineD3DDevice_SetFullscreen(iface, FALSE);
6455 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6458 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6459 return WINED3D_OK;
6462 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6464 /** FIXME: always true at the moment **/
6465 if(!bEnableDialogs) {
6466 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6468 return WINED3D_OK;
6472 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6474 TRACE("(%p) : pParameters %p\n", This, pParameters);
6476 *pParameters = This->createParms;
6477 return WINED3D_OK;
6480 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6481 IWineD3DSwapChain *swapchain;
6482 HRESULT hrc = WINED3D_OK;
6484 TRACE("Relaying to swapchain\n");
6486 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6487 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6488 IWineD3DSwapChain_Release(swapchain);
6490 return;
6493 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6494 IWineD3DSwapChain *swapchain;
6495 HRESULT hrc = WINED3D_OK;
6497 TRACE("Relaying to swapchain\n");
6499 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6500 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6501 IWineD3DSwapChain_Release(swapchain);
6503 return;
6507 /** ********************************************************
6508 * Notification functions
6509 ** ********************************************************/
6510 /** This function must be called in the release of a resource when ref == 0,
6511 * the contents of resource must still be correct,
6512 * any handels to other resource held by the caller must be closed
6513 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6514 *****************************************************/
6515 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6517 ResourceList* resourceList;
6519 TRACE("(%p) : resource %p\n", This, resource);
6520 /* add a new texture to the frot of the linked list */
6521 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6522 resourceList->resource = resource;
6524 /* Get the old head */
6525 resourceList->next = This->resources;
6527 This->resources = resourceList;
6528 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6530 return;
6533 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6535 ResourceList* resourceList = NULL;
6536 ResourceList* previousResourceList = NULL;
6538 TRACE("(%p) : resource %p\n", This, resource);
6540 resourceList = This->resources;
6542 while (resourceList != NULL) {
6543 if(resourceList->resource == resource) break;
6544 previousResourceList = resourceList;
6545 resourceList = resourceList->next;
6548 if (resourceList == NULL) {
6549 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6550 return;
6551 } else {
6552 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6554 /* make sure we don't leave a hole in the list */
6555 if (previousResourceList != NULL) {
6556 previousResourceList->next = resourceList->next;
6557 } else {
6558 This->resources = resourceList->next;
6561 return;
6565 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6567 int counter;
6569 TRACE("(%p) : resource %p\n", This, resource);
6570 switch(IWineD3DResource_GetType(resource)){
6571 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6572 case WINED3DRTYPE_SURFACE: {
6573 unsigned int i;
6575 /* Cleanup any FBO attachments if d3d is enabled */
6576 if(This->d3d_initialized) {
6577 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6578 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6579 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6580 set_render_target_fbo(iface, i, NULL);
6581 This->fbo_color_attachments[i] = NULL;
6584 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6585 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6586 set_depth_stencil_fbo(iface, NULL);
6587 This->fbo_depth_attachment = NULL;
6591 break;
6593 case WINED3DRTYPE_TEXTURE:
6594 case WINED3DRTYPE_CUBETEXTURE:
6595 case WINED3DRTYPE_VOLUMETEXTURE:
6596 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6597 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6598 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6599 This->stateBlock->textures[counter] = NULL;
6601 if (This->updateStateBlock != This->stateBlock ){
6602 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6603 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6604 This->updateStateBlock->textures[counter] = NULL;
6608 break;
6609 case WINED3DRTYPE_VOLUME:
6610 /* TODO: nothing really? */
6611 break;
6612 case WINED3DRTYPE_VERTEXBUFFER:
6613 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6615 int streamNumber;
6616 TRACE("Cleaning up stream pointers\n");
6618 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6619 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6620 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6622 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6623 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6624 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6625 This->updateStateBlock->streamSource[streamNumber] = 0;
6626 /* Set changed flag? */
6629 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) */
6630 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6631 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6632 This->stateBlock->streamSource[streamNumber] = 0;
6635 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6636 else { /* This shouldn't happen */
6637 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6639 #endif
6643 break;
6644 case WINED3DRTYPE_INDEXBUFFER:
6645 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6646 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6647 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6648 This->updateStateBlock->pIndexData = NULL;
6651 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6652 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6653 This->stateBlock->pIndexData = NULL;
6657 break;
6658 default:
6659 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6660 break;
6664 /* Remove the resoruce from the resourceStore */
6665 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6667 TRACE("Resource released\n");
6671 /**********************************************************
6672 * IWineD3DDevice VTbl follows
6673 **********************************************************/
6675 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6677 /*** IUnknown methods ***/
6678 IWineD3DDeviceImpl_QueryInterface,
6679 IWineD3DDeviceImpl_AddRef,
6680 IWineD3DDeviceImpl_Release,
6681 /*** IWineD3DDevice methods ***/
6682 IWineD3DDeviceImpl_GetParent,
6683 /*** Creation methods**/
6684 IWineD3DDeviceImpl_CreateVertexBuffer,
6685 IWineD3DDeviceImpl_CreateIndexBuffer,
6686 IWineD3DDeviceImpl_CreateStateBlock,
6687 IWineD3DDeviceImpl_CreateSurface,
6688 IWineD3DDeviceImpl_CreateTexture,
6689 IWineD3DDeviceImpl_CreateVolumeTexture,
6690 IWineD3DDeviceImpl_CreateVolume,
6691 IWineD3DDeviceImpl_CreateCubeTexture,
6692 IWineD3DDeviceImpl_CreateQuery,
6693 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6694 IWineD3DDeviceImpl_CreateVertexDeclaration,
6695 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6696 IWineD3DDeviceImpl_CreateVertexShader,
6697 IWineD3DDeviceImpl_CreatePixelShader,
6698 IWineD3DDeviceImpl_CreatePalette,
6699 /*** Odd functions **/
6700 IWineD3DDeviceImpl_Init3D,
6701 IWineD3DDeviceImpl_Uninit3D,
6702 IWineD3DDeviceImpl_SetFullscreen,
6703 IWineD3DDeviceImpl_SetMultithreaded,
6704 IWineD3DDeviceImpl_EvictManagedResources,
6705 IWineD3DDeviceImpl_GetAvailableTextureMem,
6706 IWineD3DDeviceImpl_GetBackBuffer,
6707 IWineD3DDeviceImpl_GetCreationParameters,
6708 IWineD3DDeviceImpl_GetDeviceCaps,
6709 IWineD3DDeviceImpl_GetDirect3D,
6710 IWineD3DDeviceImpl_GetDisplayMode,
6711 IWineD3DDeviceImpl_SetDisplayMode,
6712 IWineD3DDeviceImpl_GetHWND,
6713 IWineD3DDeviceImpl_SetHWND,
6714 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6715 IWineD3DDeviceImpl_GetRasterStatus,
6716 IWineD3DDeviceImpl_GetSwapChain,
6717 IWineD3DDeviceImpl_Reset,
6718 IWineD3DDeviceImpl_SetDialogBoxMode,
6719 IWineD3DDeviceImpl_SetCursorProperties,
6720 IWineD3DDeviceImpl_SetCursorPosition,
6721 IWineD3DDeviceImpl_ShowCursor,
6722 IWineD3DDeviceImpl_TestCooperativeLevel,
6723 /*** Getters and setters **/
6724 IWineD3DDeviceImpl_SetClipPlane,
6725 IWineD3DDeviceImpl_GetClipPlane,
6726 IWineD3DDeviceImpl_SetClipStatus,
6727 IWineD3DDeviceImpl_GetClipStatus,
6728 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6729 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6730 IWineD3DDeviceImpl_SetDepthStencilSurface,
6731 IWineD3DDeviceImpl_GetDepthStencilSurface,
6732 IWineD3DDeviceImpl_SetFVF,
6733 IWineD3DDeviceImpl_GetFVF,
6734 IWineD3DDeviceImpl_SetGammaRamp,
6735 IWineD3DDeviceImpl_GetGammaRamp,
6736 IWineD3DDeviceImpl_SetIndices,
6737 IWineD3DDeviceImpl_GetIndices,
6738 IWineD3DDeviceImpl_SetBaseVertexIndex,
6739 IWineD3DDeviceImpl_GetBaseVertexIndex,
6740 IWineD3DDeviceImpl_SetLight,
6741 IWineD3DDeviceImpl_GetLight,
6742 IWineD3DDeviceImpl_SetLightEnable,
6743 IWineD3DDeviceImpl_GetLightEnable,
6744 IWineD3DDeviceImpl_SetMaterial,
6745 IWineD3DDeviceImpl_GetMaterial,
6746 IWineD3DDeviceImpl_SetNPatchMode,
6747 IWineD3DDeviceImpl_GetNPatchMode,
6748 IWineD3DDeviceImpl_SetPaletteEntries,
6749 IWineD3DDeviceImpl_GetPaletteEntries,
6750 IWineD3DDeviceImpl_SetPixelShader,
6751 IWineD3DDeviceImpl_GetPixelShader,
6752 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6753 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6754 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6755 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6756 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6757 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6758 IWineD3DDeviceImpl_SetRenderState,
6759 IWineD3DDeviceImpl_GetRenderState,
6760 IWineD3DDeviceImpl_SetRenderTarget,
6761 IWineD3DDeviceImpl_GetRenderTarget,
6762 IWineD3DDeviceImpl_SetFrontBackBuffers,
6763 IWineD3DDeviceImpl_SetSamplerState,
6764 IWineD3DDeviceImpl_GetSamplerState,
6765 IWineD3DDeviceImpl_SetScissorRect,
6766 IWineD3DDeviceImpl_GetScissorRect,
6767 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6768 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6769 IWineD3DDeviceImpl_SetStreamSource,
6770 IWineD3DDeviceImpl_GetStreamSource,
6771 IWineD3DDeviceImpl_SetStreamSourceFreq,
6772 IWineD3DDeviceImpl_GetStreamSourceFreq,
6773 IWineD3DDeviceImpl_SetTexture,
6774 IWineD3DDeviceImpl_GetTexture,
6775 IWineD3DDeviceImpl_SetTextureStageState,
6776 IWineD3DDeviceImpl_GetTextureStageState,
6777 IWineD3DDeviceImpl_SetTransform,
6778 IWineD3DDeviceImpl_GetTransform,
6779 IWineD3DDeviceImpl_SetVertexDeclaration,
6780 IWineD3DDeviceImpl_GetVertexDeclaration,
6781 IWineD3DDeviceImpl_SetVertexShader,
6782 IWineD3DDeviceImpl_GetVertexShader,
6783 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6784 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6785 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6786 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6787 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6788 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6789 IWineD3DDeviceImpl_SetViewport,
6790 IWineD3DDeviceImpl_GetViewport,
6791 IWineD3DDeviceImpl_MultiplyTransform,
6792 IWineD3DDeviceImpl_ValidateDevice,
6793 IWineD3DDeviceImpl_ProcessVertices,
6794 /*** State block ***/
6795 IWineD3DDeviceImpl_BeginStateBlock,
6796 IWineD3DDeviceImpl_EndStateBlock,
6797 /*** Scene management ***/
6798 IWineD3DDeviceImpl_BeginScene,
6799 IWineD3DDeviceImpl_EndScene,
6800 IWineD3DDeviceImpl_Present,
6801 IWineD3DDeviceImpl_Clear,
6802 /*** Drawing ***/
6803 IWineD3DDeviceImpl_DrawPrimitive,
6804 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6805 IWineD3DDeviceImpl_DrawPrimitiveUP,
6806 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6807 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6808 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6809 IWineD3DDeviceImpl_DrawRectPatch,
6810 IWineD3DDeviceImpl_DrawTriPatch,
6811 IWineD3DDeviceImpl_DeletePatch,
6812 IWineD3DDeviceImpl_ColorFill,
6813 IWineD3DDeviceImpl_UpdateTexture,
6814 IWineD3DDeviceImpl_UpdateSurface,
6815 IWineD3DDeviceImpl_GetFrontBufferData,
6816 /*** object tracking ***/
6817 IWineD3DDeviceImpl_ResourceReleased
6821 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6822 WINED3DRS_ALPHABLENDENABLE ,
6823 WINED3DRS_ALPHAFUNC ,
6824 WINED3DRS_ALPHAREF ,
6825 WINED3DRS_ALPHATESTENABLE ,
6826 WINED3DRS_BLENDOP ,
6827 WINED3DRS_COLORWRITEENABLE ,
6828 WINED3DRS_DESTBLEND ,
6829 WINED3DRS_DITHERENABLE ,
6830 WINED3DRS_FILLMODE ,
6831 WINED3DRS_FOGDENSITY ,
6832 WINED3DRS_FOGEND ,
6833 WINED3DRS_FOGSTART ,
6834 WINED3DRS_LASTPIXEL ,
6835 WINED3DRS_SHADEMODE ,
6836 WINED3DRS_SRCBLEND ,
6837 WINED3DRS_STENCILENABLE ,
6838 WINED3DRS_STENCILFAIL ,
6839 WINED3DRS_STENCILFUNC ,
6840 WINED3DRS_STENCILMASK ,
6841 WINED3DRS_STENCILPASS ,
6842 WINED3DRS_STENCILREF ,
6843 WINED3DRS_STENCILWRITEMASK ,
6844 WINED3DRS_STENCILZFAIL ,
6845 WINED3DRS_TEXTUREFACTOR ,
6846 WINED3DRS_WRAP0 ,
6847 WINED3DRS_WRAP1 ,
6848 WINED3DRS_WRAP2 ,
6849 WINED3DRS_WRAP3 ,
6850 WINED3DRS_WRAP4 ,
6851 WINED3DRS_WRAP5 ,
6852 WINED3DRS_WRAP6 ,
6853 WINED3DRS_WRAP7 ,
6854 WINED3DRS_ZENABLE ,
6855 WINED3DRS_ZFUNC ,
6856 WINED3DRS_ZWRITEENABLE
6859 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6860 WINED3DTSS_ADDRESSW ,
6861 WINED3DTSS_ALPHAARG0 ,
6862 WINED3DTSS_ALPHAARG1 ,
6863 WINED3DTSS_ALPHAARG2 ,
6864 WINED3DTSS_ALPHAOP ,
6865 WINED3DTSS_BUMPENVLOFFSET ,
6866 WINED3DTSS_BUMPENVLSCALE ,
6867 WINED3DTSS_BUMPENVMAT00 ,
6868 WINED3DTSS_BUMPENVMAT01 ,
6869 WINED3DTSS_BUMPENVMAT10 ,
6870 WINED3DTSS_BUMPENVMAT11 ,
6871 WINED3DTSS_COLORARG0 ,
6872 WINED3DTSS_COLORARG1 ,
6873 WINED3DTSS_COLORARG2 ,
6874 WINED3DTSS_COLOROP ,
6875 WINED3DTSS_RESULTARG ,
6876 WINED3DTSS_TEXCOORDINDEX ,
6877 WINED3DTSS_TEXTURETRANSFORMFLAGS
6880 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6881 WINED3DSAMP_ADDRESSU ,
6882 WINED3DSAMP_ADDRESSV ,
6883 WINED3DSAMP_ADDRESSW ,
6884 WINED3DSAMP_BORDERCOLOR ,
6885 WINED3DSAMP_MAGFILTER ,
6886 WINED3DSAMP_MINFILTER ,
6887 WINED3DSAMP_MIPFILTER ,
6888 WINED3DSAMP_MIPMAPLODBIAS ,
6889 WINED3DSAMP_MAXMIPLEVEL ,
6890 WINED3DSAMP_MAXANISOTROPY ,
6891 WINED3DSAMP_SRGBTEXTURE ,
6892 WINED3DSAMP_ELEMENTINDEX
6895 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6896 WINED3DRS_AMBIENT ,
6897 WINED3DRS_AMBIENTMATERIALSOURCE ,
6898 WINED3DRS_CLIPPING ,
6899 WINED3DRS_CLIPPLANEENABLE ,
6900 WINED3DRS_COLORVERTEX ,
6901 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6902 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6903 WINED3DRS_FOGDENSITY ,
6904 WINED3DRS_FOGEND ,
6905 WINED3DRS_FOGSTART ,
6906 WINED3DRS_FOGTABLEMODE ,
6907 WINED3DRS_FOGVERTEXMODE ,
6908 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6909 WINED3DRS_LIGHTING ,
6910 WINED3DRS_LOCALVIEWER ,
6911 WINED3DRS_MULTISAMPLEANTIALIAS ,
6912 WINED3DRS_MULTISAMPLEMASK ,
6913 WINED3DRS_NORMALIZENORMALS ,
6914 WINED3DRS_PATCHEDGESTYLE ,
6915 WINED3DRS_POINTSCALE_A ,
6916 WINED3DRS_POINTSCALE_B ,
6917 WINED3DRS_POINTSCALE_C ,
6918 WINED3DRS_POINTSCALEENABLE ,
6919 WINED3DRS_POINTSIZE ,
6920 WINED3DRS_POINTSIZE_MAX ,
6921 WINED3DRS_POINTSIZE_MIN ,
6922 WINED3DRS_POINTSPRITEENABLE ,
6923 WINED3DRS_RANGEFOGENABLE ,
6924 WINED3DRS_SPECULARMATERIALSOURCE ,
6925 WINED3DRS_TWEENFACTOR ,
6926 WINED3DRS_VERTEXBLEND
6929 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6930 WINED3DTSS_TEXCOORDINDEX ,
6931 WINED3DTSS_TEXTURETRANSFORMFLAGS
6934 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6935 WINED3DSAMP_DMAPOFFSET
6938 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6939 DWORD rep = StateTable[state].representative;
6940 DWORD idx;
6941 BYTE shift;
6942 UINT i;
6943 WineD3DContext *context;
6945 if(!rep) return;
6946 for(i = 0; i < This->numContexts; i++) {
6947 context = This->contexts[i];
6948 if(isStateDirty(context, rep)) continue;
6950 context->dirtyArray[context->numDirtyEntries++] = rep;
6951 idx = rep >> 5;
6952 shift = rep & 0x1f;
6953 context->isStateDirty[idx] |= (1 << shift);