push 599a9d3db769aad8dabfd10a59120f719b00f4ee
[wine/hacks.git] / dlls / wined3d / device.c
blob0a5091d5b2994c5acab1e7c245b2b71cd7bd86be
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 } else if (Type == WINED3DSBT_PIXELSTATE) {
519 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
520 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
522 object->changed.pixelShader = TRUE;
524 /* Pixel Shader Constants */
525 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
526 object->contained_ps_consts_f[i] = i;
527 object->changed.pixelShaderConstantsF[i] = TRUE;
529 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
530 for (i = 0; i < MAX_CONST_B; ++i) {
531 object->contained_ps_consts_b[i] = i;
532 object->changed.pixelShaderConstantsB[i] = TRUE;
534 object->num_contained_ps_consts_b = MAX_CONST_B;
535 for (i = 0; i < MAX_CONST_I; ++i) {
536 object->contained_ps_consts_i[i] = i;
537 object->changed.pixelShaderConstantsI[i] = TRUE;
539 object->num_contained_ps_consts_i = MAX_CONST_I;
541 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
542 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
543 object->contained_render_states[i] = SavedPixelStates_R[i];
545 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
546 for (j = 0; j < MAX_TEXTURES; j++) {
547 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
548 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
549 object->contained_tss_states[object->num_contained_tss_states].stage = j;
550 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
551 object->num_contained_tss_states++;
554 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
555 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
556 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
557 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
558 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
559 object->num_contained_sampler_states++;
563 } else if (Type == WINED3DSBT_VERTEXSTATE) {
565 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
566 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
568 object->changed.vertexShader = TRUE;
570 /* Vertex Shader Constants */
571 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
572 object->changed.vertexShaderConstantsF[i] = TRUE;
573 object->contained_vs_consts_f[i] = i;
575 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
576 for (i = 0; i < MAX_CONST_B; ++i) {
577 object->changed.vertexShaderConstantsB[i] = TRUE;
578 object->contained_vs_consts_b[i] = i;
580 object->num_contained_vs_consts_b = MAX_CONST_B;
581 for (i = 0; i < MAX_CONST_I; ++i) {
582 object->changed.vertexShaderConstantsI[i] = TRUE;
583 object->contained_vs_consts_i[i] = i;
585 object->num_contained_vs_consts_i = MAX_CONST_I;
586 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
587 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
588 object->contained_render_states[i] = SavedVertexStates_R[i];
590 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
591 for (j = 0; j < MAX_TEXTURES; j++) {
592 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
593 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
594 object->contained_tss_states[object->num_contained_tss_states].stage = j;
595 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
596 object->num_contained_tss_states++;
599 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
600 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
601 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
602 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
603 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
604 object->num_contained_sampler_states++;
608 for(j = 0; j < LIGHTMAP_SIZE; j++) {
609 struct list *e;
610 LIST_FOR_EACH(e, &object->lightMap[j]) {
611 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
612 light->changed = TRUE;
613 light->enabledChanged = TRUE;
616 } else {
617 FIXME("Unrecognized state block type %d\n", Type);
620 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
621 return WINED3D_OK;
624 /* ************************************
625 MSDN:
626 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
628 Discard
629 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
633 ******************************** */
635 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
638 unsigned int Size = 1;
639 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
640 TRACE("(%p) Create surface\n",This);
642 /** FIXME: Check ranges on the inputs are valid
643 * MSDN
644 * MultisampleQuality
645 * [in] Quality level. The valid range is between zero and one less than the level
646 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
647 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
648 * values of paired render targets, depth stencil surfaces, and the MultiSample type
649 * must all match.
650 *******************************/
654 * TODO: Discard MSDN
655 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
657 * If this flag is set, the contents of the depth stencil buffer will be
658 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
659 * with a different depth surface.
661 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
662 ***************************/
664 if(MultisampleQuality < 0) {
665 FIXME("Invalid multisample level %d\n", MultisampleQuality);
666 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
669 if(MultisampleQuality > 0) {
670 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
671 MultisampleQuality=0;
674 /** FIXME: Check that the format is supported
675 * by the device.
676 *******************************/
678 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
679 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
680 * space!
681 *********************************/
682 if (WINED3DFMT_UNKNOWN == Format) {
683 Size = 0;
684 } else if (Format == WINED3DFMT_DXT1) {
685 /* DXT1 is half byte per pixel */
686 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
688 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
689 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
690 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
691 } else {
692 /* The pitch is a multiple of 4 bytes */
693 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
694 Size *= Height;
697 /** Create and initialise the surface resource **/
698 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
699 /* "Standalone" surface */
700 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
702 object->currentDesc.Width = Width;
703 object->currentDesc.Height = Height;
704 object->currentDesc.MultiSampleType = MultiSample;
705 object->currentDesc.MultiSampleQuality = MultisampleQuality;
706 object->glDescription.level = Level;
708 /* Flags */
709 object->Flags = 0;
710 object->Flags |= Discard ? SFLAG_DISCARD : 0;
711 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
712 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
715 if (WINED3DFMT_UNKNOWN != Format) {
716 object->bytesPerPixel = tableEntry->bpp;
717 } else {
718 object->bytesPerPixel = 0;
721 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
723 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
725 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
726 * this function is too deep to need to care about things like this.
727 * Levels need to be checked too, and possibly Type since they all affect what can be done.
728 * ****************************************/
729 switch(Pool) {
730 case WINED3DPOOL_SCRATCH:
731 if(!Lockable)
732 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
733 "which are mutually exclusive, setting lockable to TRUE\n");
734 Lockable = TRUE;
735 break;
736 case WINED3DPOOL_SYSTEMMEM:
737 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
738 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
739 case WINED3DPOOL_MANAGED:
740 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
741 "Usage of DYNAMIC which are mutually exclusive, not doing "
742 "anything just telling you.\n");
743 break;
744 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
745 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
746 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
747 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
748 break;
749 default:
750 FIXME("(%p) Unknown pool %d\n", This, Pool);
751 break;
754 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
755 FIXME("Trying to create a render target that isn't in the default pool\n");
758 /* mark the texture as dirty so that it gets loaded first time around*/
759 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
760 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
761 This, Width, Height, Format, debug_d3dformat(Format),
762 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
764 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
765 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
766 This->ddraw_primary = (IWineD3DSurface *) object;
768 /* Look at the implementation and set the correct Vtable */
769 switch(Impl) {
770 case SURFACE_OPENGL:
771 /* Check if a 3D adapter is available when creating gl surfaces */
772 if(!This->adapter) {
773 ERR("OpenGL surfaces are not available without opengl\n");
774 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
775 HeapFree(GetProcessHeap(), 0, object);
776 return WINED3DERR_NOTAVAILABLE;
778 break;
780 case SURFACE_GDI:
781 object->lpVtbl = &IWineGDISurface_Vtbl;
782 break;
784 default:
785 /* To be sure to catch this */
786 ERR("Unknown requested surface implementation %d!\n", Impl);
787 IWineD3DSurface_Release((IWineD3DSurface *) object);
788 return WINED3DERR_INVALIDCALL;
791 list_init(&object->renderbuffers);
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
805 unsigned int i;
806 UINT tmpW;
807 UINT tmpH;
808 HRESULT hr;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
831 pow2Width = Width;
832 pow2Height = Height;
833 } else {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
847 if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
885 return WINED3D_OK;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
898 unsigned int i;
899 UINT tmpW;
900 UINT tmpH;
901 UINT tmpD;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
921 if (Levels == 0) {
922 object->baseTexture.levels++;
923 tmpW = Width;
924 tmpH = Height;
925 tmpD = Depth;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
936 tmpW = Width;
937 tmpH = Height;
938 tmpD = Depth;
940 for (i = 0; i < object->baseTexture.levels; i++)
942 HRESULT hr;
943 /* Create the volume */
944 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
945 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
947 if(FAILED(hr)) {
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
950 *ppVolumeTexture = NULL;
951 return hr;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
957 /* calcualte the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
960 tmpD = max(1, tmpD >> 1);
963 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
964 TRACE("(%p) : Created volume texture %p\n", This, object);
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
969 UINT Width, UINT Height, UINT Depth,
970 DWORD Usage,
971 WINED3DFORMAT Format, WINED3DPOOL Pool,
972 IWineD3DVolume** ppVolume,
973 HANDLE* pSharedHandle, IUnknown *parent) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
977 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
979 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
982 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
984 object->currentDesc.Width = Width;
985 object->currentDesc.Height = Height;
986 object->currentDesc.Depth = Depth;
987 object->bytesPerPixel = formatDesc->bpp;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object->lockable = TRUE;
991 object->locked = FALSE;
992 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
993 object->dirty = TRUE;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
998 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
999 UINT Levels, DWORD Usage,
1000 WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DCubeTexture **ppCubeTexture,
1002 HANDLE *pSharedHandle, IUnknown *parent,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1007 unsigned int i, j;
1008 UINT tmpW;
1009 HRESULT hr;
1010 unsigned int pow2EdgeLength = EdgeLength;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN >= Format) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1016 return WINED3DERR_INVALIDCALL;
1019 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1020 WARN("(%p) : Tried to create not supported cube texture\n", This);
1021 return WINED3DERR_INVALIDCALL;
1024 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1025 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1027 TRACE("(%p) Create Cube Texture\n", This);
1029 /** Non-power2 support **/
1031 /* Find the nearest pow2 match */
1032 pow2EdgeLength = 1;
1033 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1035 object->edgeLength = EdgeLength;
1036 /* TODO: support for native non-power 2 */
1037 /* Precalculated scaling for 'faked' non power of two texture coords */
1038 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1040 /* Calculate levels for mip mapping */
1041 if (Levels == 0) {
1042 object->baseTexture.levels++;
1043 tmpW = EdgeLength;
1044 while (tmpW > 1) {
1045 tmpW = max(1, tmpW >> 1);
1046 object->baseTexture.levels++;
1048 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1051 /* Generate all the surfaces */
1052 tmpW = EdgeLength;
1053 for (i = 0; i < object->baseTexture.levels; i++) {
1055 /* Create the 6 faces */
1056 for (j = 0; j < 6; j++) {
1058 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1059 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1061 if(hr!= WINED3D_OK) {
1062 /* clean up */
1063 int k;
1064 int l;
1065 for (l = 0; l < j; l++) {
1066 IWineD3DSurface_Release(object->surfaces[j][i]);
1068 for (k = 0; k < i; k++) {
1069 for (l = 0; l < 6; l++) {
1070 IWineD3DSurface_Release(object->surfaces[l][j]);
1074 FIXME("(%p) Failed to create surface\n",object);
1075 HeapFree(GetProcessHeap(),0,object);
1076 *ppCubeTexture = NULL;
1077 return hr;
1079 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1080 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1082 tmpW = max(1, tmpW >> 1);
1085 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1086 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1087 return WINED3D_OK;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1093 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1095 /* Just a check to see if we support this type of query */
1096 switch(Type) {
1097 case WINED3DQUERYTYPE_OCCLUSION:
1098 TRACE("(%p) occlusion query\n", This);
1099 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1100 hr = WINED3D_OK;
1101 else
1102 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1103 break;
1105 case WINED3DQUERYTYPE_EVENT:
1106 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1107 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1108 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1110 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1112 hr = WINED3D_OK;
1113 break;
1115 case WINED3DQUERYTYPE_VCACHE:
1116 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1117 case WINED3DQUERYTYPE_VERTEXSTATS:
1118 case WINED3DQUERYTYPE_TIMESTAMP:
1119 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1120 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1121 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1122 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1123 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1124 case WINED3DQUERYTYPE_PIXELTIMINGS:
1125 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1126 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1127 default:
1128 FIXME("(%p) Unhandled query type %d\n", This, Type);
1130 if(NULL == ppQuery || hr != WINED3D_OK) {
1131 return hr;
1134 D3DCREATEOBJECTINSTANCE(object, Query)
1135 object->type = Type;
1136 /* allocated the 'extended' data based on the type of query requested */
1137 switch(Type){
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1140 TRACE("(%p) Allocating data for an occlusion query\n", This);
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1142 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1143 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1144 break;
1146 case WINED3DQUERYTYPE_EVENT:
1147 if(GL_SUPPORT(APPLE_FENCE)) {
1148 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1149 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1150 checkGLcall("glGenFencesAPPLE");
1151 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1152 } else if(GL_SUPPORT(NV_FENCE)) {
1153 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1154 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1155 checkGLcall("glGenFencesNV");
1156 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1158 break;
1160 case WINED3DQUERYTYPE_VCACHE:
1161 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1162 case WINED3DQUERYTYPE_VERTEXSTATS:
1163 case WINED3DQUERYTYPE_TIMESTAMP:
1164 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1165 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1166 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1167 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1168 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1169 case WINED3DQUERYTYPE_PIXELTIMINGS:
1170 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1171 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1172 default:
1173 object->extendedData = 0;
1174 FIXME("(%p) Unhandled query type %d\n",This , Type);
1176 TRACE("(%p) : Created Query %p\n", This, object);
1177 return WINED3D_OK;
1180 /*****************************************************************************
1181 * IWineD3DDeviceImpl_SetupFullscreenWindow
1183 * Helper function that modifies a HWND's Style and ExStyle for proper
1184 * fullscreen use.
1186 * Params:
1187 * iface: Pointer to the IWineD3DDevice interface
1188 * window: Window to setup
1190 *****************************************************************************/
1191 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1194 LONG style, exStyle;
1195 /* Don't do anything if an original style is stored.
1196 * That shouldn't happen
1198 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1199 if (This->style || This->exStyle) {
1200 ERR("(%p): Want to change the window parameters of HWND %p, but "
1201 "another style is stored for restoration afterwards\n", This, window);
1204 /* Get the parameters and save them */
1205 style = GetWindowLongW(window, GWL_STYLE);
1206 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1207 This->style = style;
1208 This->exStyle = exStyle;
1210 /* Filter out window decorations */
1211 style &= ~WS_CAPTION;
1212 style &= ~WS_THICKFRAME;
1213 exStyle &= ~WS_EX_WINDOWEDGE;
1214 exStyle &= ~WS_EX_CLIENTEDGE;
1216 /* Make sure the window is managed, otherwise we won't get keyboard input */
1217 style |= WS_POPUP | WS_SYSMENU;
1219 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1220 This->style, This->exStyle, style, exStyle);
1222 SetWindowLongW(window, GWL_STYLE, style);
1223 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1225 /* Inform the window about the update. */
1226 SetWindowPos(window, HWND_TOP, 0, 0,
1227 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1228 ShowWindow(window, SW_NORMAL);
1231 /*****************************************************************************
1232 * IWineD3DDeviceImpl_RestoreWindow
1234 * Helper function that restores a windows' properties when taking it out
1235 * of fullscreen mode
1237 * Params:
1238 * iface: Pointer to the IWineD3DDevice interface
1239 * window: Window to setup
1241 *****************************************************************************/
1242 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1243 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1245 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1246 * switch, do nothing
1248 if (!This->style && !This->exStyle) return;
1250 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1251 This, window, This->style, This->exStyle);
1253 SetWindowLongW(window, GWL_STYLE, This->style);
1254 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1256 /* Delete the old values */
1257 This->style = 0;
1258 This->exStyle = 0;
1260 /* Inform the window about the update */
1261 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1262 0, 0, 0, 0, /* Pos, Size, ignored */
1263 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1266 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1267 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1268 IUnknown* parent,
1269 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1270 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 HDC hDc;
1274 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1275 HRESULT hr = WINED3D_OK;
1276 IUnknown *bufferParent;
1278 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1280 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1281 * does a device hold a reference to a swap chain giving them a lifetime of the device
1282 * or does the swap chain notify the device of its destruction.
1283 *******************************/
1285 /* Check the params */
1286 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1287 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1288 return WINED3DERR_INVALIDCALL;
1289 } else if (pPresentationParameters->BackBufferCount > 1) {
1290 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1293 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1295 /*********************
1296 * Lookup the window Handle and the relating X window handle
1297 ********************/
1299 /* Setup hwnd we are using, plus which display this equates to */
1300 object->win_handle = pPresentationParameters->hDeviceWindow;
1301 if (!object->win_handle) {
1302 object->win_handle = This->createParms.hFocusWindow;
1305 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1306 hDc = GetDC(object->win_handle);
1307 TRACE("Using hDc %p\n", hDc);
1309 if (NULL == hDc) {
1310 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1311 return WINED3DERR_NOTAVAILABLE;
1314 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1315 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1316 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1317 ReleaseDC(object->win_handle, hDc);
1319 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1320 * then the corresponding dimension of the client area of the hDeviceWindow
1321 * (or the focus window, if hDeviceWindow is NULL) is taken.
1322 **********************/
1324 if (pPresentationParameters->Windowed &&
1325 ((pPresentationParameters->BackBufferWidth == 0) ||
1326 (pPresentationParameters->BackBufferHeight == 0))) {
1328 RECT Rect;
1329 GetClientRect(object->win_handle, &Rect);
1331 if (pPresentationParameters->BackBufferWidth == 0) {
1332 pPresentationParameters->BackBufferWidth = Rect.right;
1333 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1335 if (pPresentationParameters->BackBufferHeight == 0) {
1336 pPresentationParameters->BackBufferHeight = Rect.bottom;
1337 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1341 /* Put the correct figures in the presentation parameters */
1342 TRACE("Copying across presentation parameters\n");
1343 object->presentParms = *pPresentationParameters;
1345 TRACE("calling rendertarget CB\n");
1346 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1347 parent,
1348 object->presentParms.BackBufferWidth,
1349 object->presentParms.BackBufferHeight,
1350 object->presentParms.BackBufferFormat,
1351 object->presentParms.MultiSampleType,
1352 object->presentParms.MultiSampleQuality,
1353 TRUE /* Lockable */,
1354 &object->frontBuffer,
1355 NULL /* pShared (always null)*/);
1356 if (object->frontBuffer != NULL) {
1357 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1358 } else {
1359 ERR("Failed to create the front buffer\n");
1360 goto error;
1364 * Create an opengl context for the display visual
1365 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1366 * use different properties after that point in time. FIXME: How to handle when requested format
1367 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1368 * it chooses is identical to the one already being used!
1369 **********************************/
1370 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1372 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1373 if(!object->context)
1374 return E_OUTOFMEMORY;
1375 object->num_contexts = 1;
1377 ENTER_GL();
1378 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1379 LEAVE_GL();
1381 if (!object->context[0]) {
1382 ERR("Failed to create a new context\n");
1383 hr = WINED3DERR_NOTAVAILABLE;
1384 goto error;
1385 } else {
1386 TRACE("Context created (HWND=%p, glContext=%p)\n",
1387 object->win_handle, object->context[0]->glCtx);
1390 /*********************
1391 * Windowed / Fullscreen
1392 *******************/
1395 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1396 * so we should really check to see if there is a fullscreen swapchain already
1397 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1398 **************************************/
1400 if (!pPresentationParameters->Windowed) {
1402 DEVMODEW devmode;
1403 HDC hdc;
1404 int bpp = 0;
1405 RECT clip_rc;
1407 /* Get info on the current display setup */
1408 hdc = GetDC(0);
1409 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1410 ReleaseDC(0, hdc);
1412 /* Change the display settings */
1413 memset(&devmode, 0, sizeof(devmode));
1414 devmode.dmSize = sizeof(devmode);
1415 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1416 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1417 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1418 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1419 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1421 /* For GetDisplayMode */
1422 This->ddraw_width = devmode.dmPelsWidth;
1423 This->ddraw_height = devmode.dmPelsHeight;
1424 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1426 IWineD3DDevice_SetFullscreen(iface, TRUE);
1428 /* And finally clip mouse to our screen */
1429 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1430 ClipCursor(&clip_rc);
1433 /*********************
1434 * Create the back, front and stencil buffers
1435 *******************/
1436 if(object->presentParms.BackBufferCount > 0) {
1437 int i;
1439 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1440 if(!object->backBuffer) {
1441 ERR("Out of memory\n");
1442 hr = E_OUTOFMEMORY;
1443 goto error;
1446 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1447 TRACE("calling rendertarget CB\n");
1448 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1449 parent,
1450 object->presentParms.BackBufferWidth,
1451 object->presentParms.BackBufferHeight,
1452 object->presentParms.BackBufferFormat,
1453 object->presentParms.MultiSampleType,
1454 object->presentParms.MultiSampleQuality,
1455 TRUE /* Lockable */,
1456 &object->backBuffer[i],
1457 NULL /* pShared (always null)*/);
1458 if(hr == WINED3D_OK && object->backBuffer[i]) {
1459 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1460 } else {
1461 ERR("Cannot create new back buffer\n");
1462 goto error;
1464 ENTER_GL();
1465 glDrawBuffer(GL_BACK);
1466 checkGLcall("glDrawBuffer(GL_BACK)");
1467 LEAVE_GL();
1469 } else {
1470 object->backBuffer = NULL;
1472 /* Single buffering - draw to front buffer */
1473 ENTER_GL();
1474 glDrawBuffer(GL_FRONT);
1475 checkGLcall("glDrawBuffer(GL_FRONT)");
1476 LEAVE_GL();
1479 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1480 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1481 TRACE("Creating depth stencil buffer\n");
1482 if (This->depthStencilBuffer == NULL ) {
1483 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1484 parent,
1485 object->presentParms.BackBufferWidth,
1486 object->presentParms.BackBufferHeight,
1487 object->presentParms.AutoDepthStencilFormat,
1488 object->presentParms.MultiSampleType,
1489 object->presentParms.MultiSampleQuality,
1490 FALSE /* FIXME: Discard */,
1491 &This->depthStencilBuffer,
1492 NULL /* pShared (always null)*/ );
1493 if (This->depthStencilBuffer != NULL)
1494 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1497 /** TODO: A check on width, height and multisample types
1498 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1499 ****************************/
1500 object->wantsDepthStencilBuffer = TRUE;
1501 } else {
1502 object->wantsDepthStencilBuffer = FALSE;
1505 TRACE("Created swapchain %p\n", object);
1506 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1507 return WINED3D_OK;
1509 error:
1510 if (object->backBuffer) {
1511 int i;
1512 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1513 if(object->backBuffer[i]) {
1514 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1515 IUnknown_Release(bufferParent); /* once for the get parent */
1516 if (IUnknown_Release(bufferParent) > 0) {
1517 FIXME("(%p) Something's still holding the back buffer\n",This);
1521 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1522 object->backBuffer = NULL;
1524 if(object->context[0])
1525 DestroyContext(This, object->context[0]);
1526 if(object->frontBuffer) {
1527 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1528 IUnknown_Release(bufferParent); /* once for the get parent */
1529 if (IUnknown_Release(bufferParent) > 0) {
1530 FIXME("(%p) Something's still holding the front buffer\n",This);
1533 HeapFree(GetProcessHeap(), 0, object);
1534 return hr;
1537 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1538 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1540 TRACE("(%p)\n", This);
1542 return This->NumberOfSwapChains;
1545 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1547 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1549 if(iSwapChain < This->NumberOfSwapChains) {
1550 *pSwapChain = This->swapchains[iSwapChain];
1551 IWineD3DSwapChain_AddRef(*pSwapChain);
1552 TRACE("(%p) returning %p\n", This, *pSwapChain);
1553 return WINED3D_OK;
1554 } else {
1555 TRACE("Swapchain out of range\n");
1556 *pSwapChain = NULL;
1557 return WINED3DERR_INVALIDCALL;
1561 /*****
1562 * Vertex Declaration
1563 *****/
1564 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1565 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1567 IWineD3DVertexDeclarationImpl *object = NULL;
1568 HRESULT hr = WINED3D_OK;
1570 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1571 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1573 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1575 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1577 return hr;
1580 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1582 unsigned int idx, idx2;
1583 unsigned int offset;
1584 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1585 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1586 BOOL has_blend_idx = has_blend &&
1587 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1588 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1589 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1590 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1591 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1592 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1593 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1595 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1596 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1598 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1599 WINED3DVERTEXELEMENT *elements = NULL;
1601 unsigned int size;
1602 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1603 if (has_blend_idx) num_blends--;
1605 /* Compute declaration size */
1606 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1607 has_psize + has_diffuse + has_specular + num_textures + 1;
1609 /* convert the declaration */
1610 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1611 if (!elements)
1612 return 0;
1614 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1615 idx = 0;
1616 if (has_pos) {
1617 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1618 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1619 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1621 else {
1622 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1623 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1625 elements[idx].UsageIndex = 0;
1626 idx++;
1628 if (has_blend && (num_blends > 0)) {
1629 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1630 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1631 else
1632 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1633 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1634 elements[idx].UsageIndex = 0;
1635 idx++;
1637 if (has_blend_idx) {
1638 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1639 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1640 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1641 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1642 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1643 else
1644 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1645 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1646 elements[idx].UsageIndex = 0;
1647 idx++;
1649 if (has_normal) {
1650 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1651 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1652 elements[idx].UsageIndex = 0;
1653 idx++;
1655 if (has_psize) {
1656 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1657 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1658 elements[idx].UsageIndex = 0;
1659 idx++;
1661 if (has_diffuse) {
1662 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1663 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1664 elements[idx].UsageIndex = 0;
1665 idx++;
1667 if (has_specular) {
1668 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1669 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1670 elements[idx].UsageIndex = 1;
1671 idx++;
1673 for (idx2 = 0; idx2 < num_textures; idx2++) {
1674 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1675 switch (numcoords) {
1676 case WINED3DFVF_TEXTUREFORMAT1:
1677 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1678 break;
1679 case WINED3DFVF_TEXTUREFORMAT2:
1680 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1681 break;
1682 case WINED3DFVF_TEXTUREFORMAT3:
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1684 break;
1685 case WINED3DFVF_TEXTUREFORMAT4:
1686 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1687 break;
1689 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1690 elements[idx].UsageIndex = idx2;
1691 idx++;
1694 /* Now compute offsets, and initialize the rest of the fields */
1695 for (idx = 0, offset = 0; idx < size-1; idx++) {
1696 elements[idx].Stream = 0;
1697 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1698 elements[idx].Offset = offset;
1699 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1702 *ppVertexElements = elements;
1703 return size;
1706 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1707 WINED3DVERTEXELEMENT* elements = NULL;
1708 size_t size;
1709 DWORD hr;
1711 size = ConvertFvfToDeclaration(Fvf, &elements);
1712 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1714 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1715 HeapFree(GetProcessHeap(), 0, elements);
1716 if (hr != S_OK) return hr;
1718 return WINED3D_OK;
1721 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1722 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1724 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1725 HRESULT hr = WINED3D_OK;
1726 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1727 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1729 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1731 if (vertex_declaration) {
1732 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1735 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1737 if (WINED3D_OK != hr) {
1738 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1739 IWineD3DVertexShader_Release(*ppVertexShader);
1740 return WINED3DERR_INVALIDCALL;
1743 return WINED3D_OK;
1746 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1748 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1749 HRESULT hr = WINED3D_OK;
1751 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1752 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1753 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1754 if (WINED3D_OK == hr) {
1755 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1756 } else {
1757 WARN("(%p) : Failed to create pixel shader\n", This);
1760 return hr;
1763 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1765 IWineD3DPaletteImpl *object;
1766 HRESULT hr;
1767 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1769 /* Create the new object */
1770 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1771 if(!object) {
1772 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1773 return E_OUTOFMEMORY;
1776 object->lpVtbl = &IWineD3DPalette_Vtbl;
1777 object->ref = 1;
1778 object->Flags = Flags;
1779 object->parent = Parent;
1780 object->wineD3DDevice = This;
1781 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1783 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1785 if(!object->hpal) {
1786 HeapFree( GetProcessHeap(), 0, object);
1787 return E_OUTOFMEMORY;
1790 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1791 if(FAILED(hr)) {
1792 IWineD3DPalette_Release((IWineD3DPalette *) object);
1793 return hr;
1796 *Palette = (IWineD3DPalette *) object;
1798 return WINED3D_OK;
1801 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1802 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1803 IWineD3DSwapChainImpl *swapchain;
1804 HRESULT hr;
1805 DWORD state;
1807 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1808 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1810 /* TODO: Test if OpenGL is compiled in and loaded */
1812 TRACE("(%p) : Creating stateblock\n", This);
1813 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1814 hr = IWineD3DDevice_CreateStateBlock(iface,
1815 WINED3DSBT_INIT,
1816 (IWineD3DStateBlock **)&This->stateBlock,
1817 NULL);
1818 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1819 WARN("Failed to create stateblock\n");
1820 return hr;
1822 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1823 This->updateStateBlock = This->stateBlock;
1824 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1826 hr = allocate_shader_constants(This->updateStateBlock);
1827 if (WINED3D_OK != hr)
1828 return hr;
1830 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1831 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1832 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1834 /* Initialize the texture unit mapping to a 1:1 mapping */
1835 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1836 if (state < GL_LIMITS(fragment_samplers)) {
1837 This->texUnitMap[state] = state;
1838 This->rev_tex_unit_map[state] = state;
1839 } else {
1840 This->texUnitMap[state] = -1;
1841 This->rev_tex_unit_map[state] = -1;
1845 /* Setup the implicit swapchain */
1846 TRACE("Creating implicit swapchain\n");
1847 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1848 if (FAILED(hr) || !swapchain) {
1849 WARN("Failed to create implicit swapchain\n");
1850 return hr;
1853 This->NumberOfSwapChains = 1;
1854 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1855 if(!This->swapchains) {
1856 ERR("Out of memory!\n");
1857 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1858 return E_OUTOFMEMORY;
1860 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1862 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1864 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1865 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1866 This->render_targets[0] = swapchain->backBuffer[0];
1867 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1869 else {
1870 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1871 This->render_targets[0] = swapchain->frontBuffer;
1872 This->lastActiveRenderTarget = swapchain->frontBuffer;
1874 IWineD3DSurface_AddRef(This->render_targets[0]);
1875 This->activeContext = swapchain->context[0];
1876 This->lastThread = GetCurrentThreadId();
1878 /* Depth Stencil support */
1879 This->stencilBufferTarget = This->depthStencilBuffer;
1880 if (NULL != This->stencilBufferTarget) {
1881 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1884 /* Set up some starting GL setup */
1885 ENTER_GL();
1887 /* Setup all the devices defaults */
1888 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1889 #if 0
1890 IWineD3DImpl_CheckGraphicsMemory();
1891 #endif
1893 { /* Set a default viewport */
1894 WINED3DVIEWPORT vp;
1895 vp.X = 0;
1896 vp.Y = 0;
1897 vp.Width = pPresentationParameters->BackBufferWidth;
1898 vp.Height = pPresentationParameters->BackBufferHeight;
1899 vp.MinZ = 0.0f;
1900 vp.MaxZ = 1.0f;
1901 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1904 /* Initialize the current view state */
1905 This->view_ident = 1;
1906 This->contexts[0]->last_was_rhw = 0;
1907 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1908 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1910 switch(wined3d_settings.offscreen_rendering_mode) {
1911 case ORM_FBO:
1912 case ORM_PBUFFER:
1913 This->offscreenBuffer = GL_BACK;
1914 break;
1916 case ORM_BACKBUFFER:
1918 if(GL_LIMITS(aux_buffers) > 0) {
1919 TRACE("Using auxilliary buffer for offscreen rendering\n");
1920 This->offscreenBuffer = GL_AUX0;
1921 } else {
1922 TRACE("Using back buffer for offscreen rendering\n");
1923 This->offscreenBuffer = GL_BACK;
1928 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1929 LEAVE_GL();
1931 /* Clear the screen */
1932 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1933 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1934 0x00, 1.0, 0);
1936 This->d3d_initialized = TRUE;
1937 return WINED3D_OK;
1940 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1942 int sampler;
1943 UINT i;
1944 TRACE("(%p)\n", This);
1946 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1948 /* I don't think that the interface guarants that the device is destroyed from the same thread
1949 * it was created. Thus make sure a context is active for the glDelete* calls
1951 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1953 TRACE("Deleting high order patches\n");
1954 for(i = 0; i < PATCHMAP_SIZE; i++) {
1955 struct list *e1, *e2;
1956 struct WineD3DRectPatch *patch;
1957 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1958 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1959 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1963 /* Delete the pbuffer context if there is any */
1964 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1966 /* Delete the mouse cursor texture */
1967 if(This->cursorTexture) {
1968 ENTER_GL();
1969 glDeleteTextures(1, &This->cursorTexture);
1970 LEAVE_GL();
1971 This->cursorTexture = 0;
1974 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1975 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1977 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1978 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1981 /* Release the update stateblock */
1982 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1983 if(This->updateStateBlock != This->stateBlock)
1984 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1986 This->updateStateBlock = NULL;
1988 { /* because were not doing proper internal refcounts releasing the primary state block
1989 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1990 to set this->stateBlock = NULL; first */
1991 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1992 This->stateBlock = NULL;
1994 /* Release the stateblock */
1995 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1996 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2000 /* Release the buffers (with sanity checks)*/
2001 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2002 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2003 if(This->depthStencilBuffer != This->stencilBufferTarget)
2004 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2006 This->stencilBufferTarget = NULL;
2008 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2009 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2010 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2012 TRACE("Setting rendertarget to NULL\n");
2013 This->render_targets[0] = NULL;
2015 if (This->depthStencilBuffer) {
2016 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2017 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2019 This->depthStencilBuffer = NULL;
2022 for(i=0; i < This->NumberOfSwapChains; i++) {
2023 TRACE("Releasing the implicit swapchain %d\n", i);
2024 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2025 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2029 HeapFree(GetProcessHeap(), 0, This->swapchains);
2030 This->swapchains = NULL;
2031 This->NumberOfSwapChains = 0;
2033 HeapFree(GetProcessHeap(), 0, This->render_targets);
2034 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2035 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2036 This->render_targets = NULL;
2037 This->fbo_color_attachments = NULL;
2038 This->draw_buffers = NULL;
2041 This->d3d_initialized = FALSE;
2042 return WINED3D_OK;
2045 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2047 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2049 /* Setup the window for fullscreen mode */
2050 if(fullscreen && !This->ddraw_fullscreen) {
2051 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2052 } else if(!fullscreen && This->ddraw_fullscreen) {
2053 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2056 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2057 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2058 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2059 * separately.
2061 This->ddraw_fullscreen = fullscreen;
2064 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2065 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2066 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2068 * There is no way to deactivate thread safety once it is enabled
2070 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2073 /*For now just store the flag(needed in case of ddraw) */
2074 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2076 return;
2079 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2080 DEVMODEW devmode;
2081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2082 LONG ret;
2083 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2084 RECT clip_rc;
2086 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2088 /* Resize the screen even without a window:
2089 * The app could have unset it with SetCooperativeLevel, but not called
2090 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2091 * but we don't have any hwnd
2094 memset(&devmode, 0, sizeof(devmode));
2095 devmode.dmSize = sizeof(devmode);
2096 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2097 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2098 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2099 devmode.dmPelsWidth = pMode->Width;
2100 devmode.dmPelsHeight = pMode->Height;
2102 devmode.dmDisplayFrequency = pMode->RefreshRate;
2103 if (pMode->RefreshRate != 0) {
2104 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2107 /* Only change the mode if necessary */
2108 if( (This->ddraw_width == pMode->Width) &&
2109 (This->ddraw_height == pMode->Height) &&
2110 (This->ddraw_format == pMode->Format) &&
2111 (pMode->RefreshRate == 0) ) {
2112 return WINED3D_OK;
2115 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2116 if (ret != DISP_CHANGE_SUCCESSFUL) {
2117 if(devmode.dmDisplayFrequency != 0) {
2118 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2119 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2120 devmode.dmDisplayFrequency = 0;
2121 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2123 if(ret != DISP_CHANGE_SUCCESSFUL) {
2124 return WINED3DERR_NOTAVAILABLE;
2128 /* Store the new values */
2129 This->ddraw_width = pMode->Width;
2130 This->ddraw_height = pMode->Height;
2131 This->ddraw_format = pMode->Format;
2133 /* Only do this with a window of course */
2134 if(This->ddraw_window)
2135 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2137 /* And finally clip mouse to our screen */
2138 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2139 ClipCursor(&clip_rc);
2141 return WINED3D_OK;
2144 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2146 *ppD3D= This->wineD3D;
2147 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2148 IWineD3D_AddRef(*ppD3D);
2149 return WINED3D_OK;
2152 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2153 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2154 * into the video ram as possible and seeing how many fit
2155 * you can also get the correct initial value from nvidia and ATI's driver via X
2156 * texture memory is video memory + AGP memory
2157 *******************/
2158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2159 static BOOL showfixmes = TRUE;
2160 if (showfixmes) {
2161 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2162 (wined3d_settings.emulated_textureram/(1024*1024)),
2163 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2164 showfixmes = FALSE;
2166 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2167 (wined3d_settings.emulated_textureram/(1024*1024)),
2168 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2169 /* return simulated texture memory left */
2170 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2175 /*****
2176 * Get / Set FVF
2177 *****/
2178 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2179 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2181 /* Update the current state block */
2182 This->updateStateBlock->changed.fvf = TRUE;
2184 if(This->updateStateBlock->fvf == fvf) {
2185 TRACE("Application is setting the old fvf over, nothing to do\n");
2186 return WINED3D_OK;
2189 This->updateStateBlock->fvf = fvf;
2190 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2191 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2192 return WINED3D_OK;
2196 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2198 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2199 *pfvf = This->stateBlock->fvf;
2200 return WINED3D_OK;
2203 /*****
2204 * Get / Set Stream Source
2205 *****/
2206 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2208 IWineD3DVertexBuffer *oldSrc;
2210 if (StreamNumber >= MAX_STREAMS) {
2211 WARN("Stream out of range %d\n", StreamNumber);
2212 return WINED3DERR_INVALIDCALL;
2215 oldSrc = This->stateBlock->streamSource[StreamNumber];
2216 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2218 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2220 if(oldSrc == pStreamData &&
2221 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2222 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2223 TRACE("Application is setting the old values over, nothing to do\n");
2224 return WINED3D_OK;
2227 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2228 if (pStreamData) {
2229 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2230 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2233 /* Handle recording of state blocks */
2234 if (This->isRecordingState) {
2235 TRACE("Recording... not performing anything\n");
2236 return WINED3D_OK;
2239 /* Need to do a getParent and pass the reffs up */
2240 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2241 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2242 so for now, just count internally */
2243 if (pStreamData != NULL) {
2244 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2245 InterlockedIncrement(&vbImpl->bindCount);
2246 IWineD3DVertexBuffer_AddRef(pStreamData);
2248 if (oldSrc != NULL) {
2249 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2250 IWineD3DVertexBuffer_Release(oldSrc);
2253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2255 return WINED3D_OK;
2258 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2261 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2262 This->stateBlock->streamSource[StreamNumber],
2263 This->stateBlock->streamOffset[StreamNumber],
2264 This->stateBlock->streamStride[StreamNumber]);
2266 if (StreamNumber >= MAX_STREAMS) {
2267 WARN("Stream out of range %d\n", StreamNumber);
2268 return WINED3DERR_INVALIDCALL;
2270 *pStream = This->stateBlock->streamSource[StreamNumber];
2271 *pStride = This->stateBlock->streamStride[StreamNumber];
2272 if (pOffset) {
2273 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2276 if (*pStream != NULL) {
2277 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2279 return WINED3D_OK;
2282 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2284 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2285 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2287 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2288 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2290 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2291 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2293 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2294 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2295 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2298 return WINED3D_OK;
2301 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2304 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2305 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2307 TRACE("(%p) : returning %d\n", This, *Divider);
2309 return WINED3D_OK;
2312 /*****
2313 * Get / Set & Multiply Transform
2314 *****/
2315 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2318 /* Most of this routine, comments included copied from ddraw tree initially: */
2319 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2321 /* Handle recording of state blocks */
2322 if (This->isRecordingState) {
2323 TRACE("Recording... not performing anything\n");
2324 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2325 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2326 return WINED3D_OK;
2330 * If the new matrix is the same as the current one,
2331 * we cut off any further processing. this seems to be a reasonable
2332 * optimization because as was noticed, some apps (warcraft3 for example)
2333 * tend towards setting the same matrix repeatedly for some reason.
2335 * From here on we assume that the new matrix is different, wherever it matters.
2337 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2338 TRACE("The app is setting the same matrix over again\n");
2339 return WINED3D_OK;
2340 } else {
2341 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2345 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2346 where ViewMat = Camera space, WorldMat = world space.
2348 In OpenGL, camera and world space is combined into GL_MODELVIEW
2349 matrix. The Projection matrix stay projection matrix.
2352 /* Capture the times we can just ignore the change for now */
2353 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2354 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2355 /* Handled by the state manager */
2358 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2359 return WINED3D_OK;
2362 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2364 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2365 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2366 return WINED3D_OK;
2369 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2370 WINED3DMATRIX *mat = NULL;
2371 WINED3DMATRIX temp;
2373 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2374 * below means it will be recorded in a state block change, but it
2375 * works regardless where it is recorded.
2376 * If this is found to be wrong, change to StateBlock.
2378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2381 if (State < HIGHEST_TRANSFORMSTATE)
2383 mat = &This->updateStateBlock->transforms[State];
2384 } else {
2385 FIXME("Unhandled transform state!!\n");
2388 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2390 /* Apply change via set transform - will reapply to eg. lights this way */
2391 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2394 /*****
2395 * Get / Set Light
2396 *****/
2397 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2398 you can reference any indexes you want as long as that number max are enabled at any
2399 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2400 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2401 but when recording, just build a chain pretty much of commands to be replayed. */
2403 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2404 float rho;
2405 PLIGHTINFOEL *object = NULL;
2406 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2407 struct list *e;
2409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2410 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2412 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2413 * the gl driver.
2415 if(!pLight) {
2416 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2417 return WINED3DERR_INVALIDCALL;
2420 switch(pLight->Type) {
2421 case WINED3DLIGHT_POINT:
2422 case WINED3DLIGHT_SPOT:
2423 case WINED3DLIGHT_PARALLELPOINT:
2424 case WINED3DLIGHT_GLSPOT:
2425 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2426 * most wanted
2428 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2429 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2430 return WINED3DERR_INVALIDCALL;
2432 break;
2434 case WINED3DLIGHT_DIRECTIONAL:
2435 /* Ignores attenuation */
2436 break;
2438 default:
2439 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2440 return WINED3DERR_INVALIDCALL;
2443 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2444 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2445 if(object->OriginalIndex == Index) break;
2446 object = NULL;
2449 if(!object) {
2450 TRACE("Adding new light\n");
2451 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2452 if(!object) {
2453 ERR("Out of memory error when allocating a light\n");
2454 return E_OUTOFMEMORY;
2456 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2457 object->glIndex = -1;
2458 object->OriginalIndex = Index;
2459 object->changed = TRUE;
2462 /* Initialize the object */
2463 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,
2464 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2465 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2466 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2467 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2468 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2469 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2471 /* Save away the information */
2472 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2474 switch (pLight->Type) {
2475 case WINED3DLIGHT_POINT:
2476 /* Position */
2477 object->lightPosn[0] = pLight->Position.x;
2478 object->lightPosn[1] = pLight->Position.y;
2479 object->lightPosn[2] = pLight->Position.z;
2480 object->lightPosn[3] = 1.0f;
2481 object->cutoff = 180.0f;
2482 /* FIXME: Range */
2483 break;
2485 case WINED3DLIGHT_DIRECTIONAL:
2486 /* Direction */
2487 object->lightPosn[0] = -pLight->Direction.x;
2488 object->lightPosn[1] = -pLight->Direction.y;
2489 object->lightPosn[2] = -pLight->Direction.z;
2490 object->lightPosn[3] = 0.0;
2491 object->exponent = 0.0f;
2492 object->cutoff = 180.0f;
2493 break;
2495 case WINED3DLIGHT_SPOT:
2496 /* Position */
2497 object->lightPosn[0] = pLight->Position.x;
2498 object->lightPosn[1] = pLight->Position.y;
2499 object->lightPosn[2] = pLight->Position.z;
2500 object->lightPosn[3] = 1.0;
2502 /* Direction */
2503 object->lightDirn[0] = pLight->Direction.x;
2504 object->lightDirn[1] = pLight->Direction.y;
2505 object->lightDirn[2] = pLight->Direction.z;
2506 object->lightDirn[3] = 1.0;
2509 * opengl-ish and d3d-ish spot lights use too different models for the
2510 * light "intensity" as a function of the angle towards the main light direction,
2511 * so we only can approximate very roughly.
2512 * however spot lights are rather rarely used in games (if ever used at all).
2513 * furthermore if still used, probably nobody pays attention to such details.
2515 if (pLight->Falloff == 0) {
2516 rho = 6.28f;
2517 } else {
2518 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2520 if (rho < 0.0001) rho = 0.0001f;
2521 object->exponent = -0.3/log(cos(rho/2));
2522 if (object->exponent > 128.0) {
2523 object->exponent = 128.0;
2525 object->cutoff = pLight->Phi*90/M_PI;
2527 /* FIXME: Range */
2528 break;
2530 default:
2531 FIXME("Unrecognized light type %d\n", pLight->Type);
2534 /* Update the live definitions if the light is currently assigned a glIndex */
2535 if (object->glIndex != -1 && !This->isRecordingState) {
2536 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2538 return WINED3D_OK;
2541 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2542 PLIGHTINFOEL *lightInfo = NULL;
2543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2544 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2545 struct list *e;
2546 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2548 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2549 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2550 if(lightInfo->OriginalIndex == Index) break;
2551 lightInfo = NULL;
2554 if (lightInfo == NULL) {
2555 TRACE("Light information requested but light not defined\n");
2556 return WINED3DERR_INVALIDCALL;
2559 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2560 return WINED3D_OK;
2563 /*****
2564 * Get / Set Light Enable
2565 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2566 *****/
2567 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2568 PLIGHTINFOEL *lightInfo = NULL;
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2571 struct list *e;
2572 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2574 /* Tests show true = 128...not clear why */
2575 Enable = Enable? 128: 0;
2577 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2578 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2579 if(lightInfo->OriginalIndex == Index) break;
2580 lightInfo = NULL;
2582 TRACE("Found light: %p\n", lightInfo);
2584 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2585 if (lightInfo == NULL) {
2587 TRACE("Light enabled requested but light not defined, so defining one!\n");
2588 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2590 /* Search for it again! Should be fairly quick as near head of list */
2591 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2592 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2593 if(lightInfo->OriginalIndex == Index) break;
2594 lightInfo = NULL;
2596 if (lightInfo == NULL) {
2597 FIXME("Adding default lights has failed dismally\n");
2598 return WINED3DERR_INVALIDCALL;
2602 lightInfo->enabledChanged = TRUE;
2603 if(!Enable) {
2604 if(lightInfo->glIndex != -1) {
2605 if(!This->isRecordingState) {
2606 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2609 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2610 lightInfo->glIndex = -1;
2611 } else {
2612 TRACE("Light already disabled, nothing to do\n");
2614 } else {
2615 if (lightInfo->glIndex != -1) {
2616 /* nop */
2617 TRACE("Nothing to do as light was enabled\n");
2618 } else {
2619 int i;
2620 /* Find a free gl light */
2621 for(i = 0; i < This->maxConcurrentLights; i++) {
2622 if(This->stateBlock->activeLights[i] == NULL) {
2623 This->stateBlock->activeLights[i] = lightInfo;
2624 lightInfo->glIndex = i;
2625 break;
2628 if(lightInfo->glIndex == -1) {
2629 ERR("Too many concurrently active lights\n");
2630 return WINED3DERR_INVALIDCALL;
2633 /* i == lightInfo->glIndex */
2634 if(!This->isRecordingState) {
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2640 return WINED3D_OK;
2643 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2645 PLIGHTINFOEL *lightInfo = NULL;
2646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2647 struct list *e;
2648 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2649 TRACE("(%p) : for idx(%d)\n", This, Index);
2651 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2652 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2653 if(lightInfo->OriginalIndex == Index) break;
2654 lightInfo = NULL;
2657 if (lightInfo == NULL) {
2658 TRACE("Light enabled state requested but light not defined\n");
2659 return WINED3DERR_INVALIDCALL;
2661 /* true is 128 according to SetLightEnable */
2662 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2663 return WINED3D_OK;
2666 /*****
2667 * Get / Set Clip Planes
2668 *****/
2669 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2671 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2673 /* Validate Index */
2674 if (Index >= GL_LIMITS(clipplanes)) {
2675 TRACE("Application has requested clipplane this device doesn't support\n");
2676 return WINED3DERR_INVALIDCALL;
2679 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2681 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2682 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2683 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2684 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2685 TRACE("Application is setting old values over, nothing to do\n");
2686 return WINED3D_OK;
2689 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2690 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2691 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2692 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2694 /* Handle recording of state blocks */
2695 if (This->isRecordingState) {
2696 TRACE("Recording... not performing anything\n");
2697 return WINED3D_OK;
2700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2702 return WINED3D_OK;
2705 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2707 TRACE("(%p) : for idx %d\n", This, Index);
2709 /* Validate Index */
2710 if (Index >= GL_LIMITS(clipplanes)) {
2711 TRACE("Application has requested clipplane this device doesn't support\n");
2712 return WINED3DERR_INVALIDCALL;
2715 pPlane[0] = This->stateBlock->clipplane[Index][0];
2716 pPlane[1] = This->stateBlock->clipplane[Index][1];
2717 pPlane[2] = This->stateBlock->clipplane[Index][2];
2718 pPlane[3] = This->stateBlock->clipplane[Index][3];
2719 return WINED3D_OK;
2722 /*****
2723 * Get / Set Clip Plane Status
2724 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2725 *****/
2726 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2728 FIXME("(%p) : stub\n", This);
2729 if (NULL == pClipStatus) {
2730 return WINED3DERR_INVALIDCALL;
2732 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2733 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2734 return WINED3D_OK;
2737 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2739 FIXME("(%p) : stub\n", This);
2740 if (NULL == pClipStatus) {
2741 return WINED3DERR_INVALIDCALL;
2743 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2744 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2745 return WINED3D_OK;
2748 /*****
2749 * Get / Set Material
2750 *****/
2751 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2754 This->updateStateBlock->changed.material = TRUE;
2755 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2757 /* Handle recording of state blocks */
2758 if (This->isRecordingState) {
2759 TRACE("Recording... not performing anything\n");
2760 return WINED3D_OK;
2763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2764 return WINED3D_OK;
2767 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2769 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2770 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2771 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2772 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2773 pMaterial->Ambient.b, pMaterial->Ambient.a);
2774 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2775 pMaterial->Specular.b, pMaterial->Specular.a);
2776 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2777 pMaterial->Emissive.b, pMaterial->Emissive.a);
2778 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2780 return WINED3D_OK;
2783 /*****
2784 * Get / Set Indices
2785 *****/
2786 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2788 IWineD3DIndexBuffer *oldIdxs;
2790 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2791 oldIdxs = This->updateStateBlock->pIndexData;
2793 This->updateStateBlock->changed.indices = TRUE;
2794 This->updateStateBlock->pIndexData = pIndexData;
2796 /* Handle recording of state blocks */
2797 if (This->isRecordingState) {
2798 TRACE("Recording... not performing anything\n");
2799 return WINED3D_OK;
2802 if(oldIdxs != pIndexData) {
2803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2804 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2805 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2807 return WINED3D_OK;
2810 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 *ppIndexData = This->stateBlock->pIndexData;
2815 /* up ref count on ppindexdata */
2816 if (*ppIndexData) {
2817 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2818 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2819 }else{
2820 TRACE("(%p) No index data set\n", This);
2822 TRACE("Returning %p\n", *ppIndexData);
2824 return WINED3D_OK;
2827 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2828 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 TRACE("(%p)->(%d)\n", This, BaseIndex);
2832 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2833 TRACE("Application is setting the old value over, nothing to do\n");
2834 return WINED3D_OK;
2837 This->updateStateBlock->baseVertexIndex = BaseIndex;
2839 if (This->isRecordingState) {
2840 TRACE("Recording... not performing anything\n");
2841 return WINED3D_OK;
2843 /* The base vertex index affects the stream sources */
2844 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2845 return WINED3D_OK;
2848 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2850 TRACE("(%p) : base_index %p\n", This, base_index);
2852 *base_index = This->stateBlock->baseVertexIndex;
2854 TRACE("Returning %u\n", *base_index);
2856 return WINED3D_OK;
2859 /*****
2860 * Get / Set Viewports
2861 *****/
2862 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2865 TRACE("(%p)\n", This);
2866 This->updateStateBlock->changed.viewport = TRUE;
2867 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2869 /* Handle recording of state blocks */
2870 if (This->isRecordingState) {
2871 TRACE("Recording... not performing anything\n");
2872 return WINED3D_OK;
2875 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2876 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2878 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2879 return WINED3D_OK;
2883 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2884 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2885 TRACE("(%p)\n", This);
2886 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2887 return WINED3D_OK;
2890 /*****
2891 * Get / Set Render States
2892 * TODO: Verify against dx9 definitions
2893 *****/
2894 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2897 DWORD oldValue = This->stateBlock->renderState[State];
2899 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2901 This->updateStateBlock->changed.renderState[State] = TRUE;
2902 This->updateStateBlock->renderState[State] = Value;
2904 /* Handle recording of state blocks */
2905 if (This->isRecordingState) {
2906 TRACE("Recording... not performing anything\n");
2907 return WINED3D_OK;
2910 /* Compared here and not before the assignment to allow proper stateblock recording */
2911 if(Value == oldValue) {
2912 TRACE("Application is setting the old value over, nothing to do\n");
2913 } else {
2914 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2917 return WINED3D_OK;
2920 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2922 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2923 *pValue = This->stateBlock->renderState[State];
2924 return WINED3D_OK;
2927 /*****
2928 * Get / Set Sampler States
2929 * TODO: Verify against dx9 definitions
2930 *****/
2932 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2934 DWORD oldValue;
2936 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2937 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2939 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2940 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2944 * SetSampler is designed to allow for more than the standard up to 8 textures
2945 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2946 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2948 * http://developer.nvidia.com/object/General_FAQ.html#t6
2950 * There are two new settings for GForce
2951 * the sampler one:
2952 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2953 * and the texture one:
2954 * GL_MAX_TEXTURE_COORDS_ARB.
2955 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2956 ******************/
2958 oldValue = This->stateBlock->samplerState[Sampler][Type];
2959 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2960 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2962 /* Handle recording of state blocks */
2963 if (This->isRecordingState) {
2964 TRACE("Recording... not performing anything\n");
2965 return WINED3D_OK;
2968 if(oldValue == Value) {
2969 TRACE("Application is setting the old value over, nothing to do\n");
2970 return WINED3D_OK;
2973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2975 return WINED3D_OK;
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2981 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2982 This, Sampler, debug_d3dsamplerstate(Type), Type);
2984 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2985 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2988 *Value = This->stateBlock->samplerState[Sampler][Type];
2989 TRACE("(%p) : Returning %#x\n", This, *Value);
2991 return WINED3D_OK;
2994 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2995 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2997 This->updateStateBlock->changed.scissorRect = TRUE;
2998 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2999 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3000 return WINED3D_OK;
3002 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3004 if(This->isRecordingState) {
3005 TRACE("Recording... not performing anything\n");
3006 return WINED3D_OK;
3009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3011 return WINED3D_OK;
3014 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3018 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3019 return WINED3D_OK;
3022 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3023 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3024 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3026 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3028 This->updateStateBlock->vertexDecl = pDecl;
3029 This->updateStateBlock->changed.vertexDecl = TRUE;
3031 if (This->isRecordingState) {
3032 TRACE("Recording... not performing anything\n");
3033 return WINED3D_OK;
3034 } else if(pDecl == oldDecl) {
3035 /* Checked after the assignment to allow proper stateblock recording */
3036 TRACE("Application is setting the old declaration over, nothing to do\n");
3037 return WINED3D_OK;
3040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3041 return WINED3D_OK;
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3047 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3049 *ppDecl = This->stateBlock->vertexDecl;
3050 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3051 return WINED3D_OK;
3054 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3056 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3058 This->updateStateBlock->vertexShader = pShader;
3059 This->updateStateBlock->changed.vertexShader = TRUE;
3061 if (This->isRecordingState) {
3062 TRACE("Recording... not performing anything\n");
3063 return WINED3D_OK;
3064 } else if(oldShader == pShader) {
3065 /* Checked here to allow proper stateblock recording */
3066 TRACE("App is setting the old shader over, nothing to do\n");
3067 return WINED3D_OK;
3070 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3074 return WINED3D_OK;
3077 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 if (NULL == ppShader) {
3081 return WINED3DERR_INVALIDCALL;
3083 *ppShader = This->stateBlock->vertexShader;
3084 if( NULL != *ppShader)
3085 IWineD3DVertexShader_AddRef(*ppShader);
3087 TRACE("(%p) : returning %p\n", This, *ppShader);
3088 return WINED3D_OK;
3091 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3092 IWineD3DDevice *iface,
3093 UINT start,
3094 CONST BOOL *srcData,
3095 UINT count) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3098 int i, cnt = min(count, MAX_CONST_B - start);
3100 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3101 iface, srcData, start, count);
3103 if (srcData == NULL || cnt < 0)
3104 return WINED3DERR_INVALIDCALL;
3106 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3107 for (i = 0; i < cnt; i++)
3108 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3110 for (i = start; i < cnt + start; ++i) {
3111 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3116 return WINED3D_OK;
3119 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3120 IWineD3DDevice *iface,
3121 UINT start,
3122 BOOL *dstData,
3123 UINT count) {
3125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3126 int cnt = min(count, MAX_CONST_B - start);
3128 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3129 iface, dstData, start, count);
3131 if (dstData == NULL || cnt < 0)
3132 return WINED3DERR_INVALIDCALL;
3134 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3135 return WINED3D_OK;
3138 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3139 IWineD3DDevice *iface,
3140 UINT start,
3141 CONST int *srcData,
3142 UINT count) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 int i, cnt = min(count, MAX_CONST_I - start);
3147 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3148 iface, srcData, start, count);
3150 if (srcData == NULL || cnt < 0)
3151 return WINED3DERR_INVALIDCALL;
3153 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3154 for (i = 0; i < cnt; i++)
3155 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3156 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3158 for (i = start; i < cnt + start; ++i) {
3159 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3164 return WINED3D_OK;
3167 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3168 IWineD3DDevice *iface,
3169 UINT start,
3170 int *dstData,
3171 UINT count) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 int cnt = min(count, MAX_CONST_I - start);
3176 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3177 iface, dstData, start, count);
3179 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3180 return WINED3DERR_INVALIDCALL;
3182 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3183 return WINED3D_OK;
3186 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3187 IWineD3DDevice *iface,
3188 UINT start,
3189 CONST float *srcData,
3190 UINT count) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 int i;
3195 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3196 iface, srcData, start, count);
3198 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3199 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3200 return WINED3DERR_INVALIDCALL;
3202 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3203 if(TRACE_ON(d3d)) {
3204 for (i = 0; i < count; i++)
3205 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3206 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3209 for (i = start; i < count + start; ++i) {
3210 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3211 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3212 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3213 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3214 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3216 ptr->idx[ptr->count++] = i;
3217 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3223 return WINED3D_OK;
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3227 IWineD3DDevice *iface,
3228 UINT start,
3229 float *dstData,
3230 UINT count) {
3232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3235 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3236 iface, dstData, start, count);
3238 if (dstData == NULL || cnt < 0)
3239 return WINED3DERR_INVALIDCALL;
3241 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3242 return WINED3D_OK;
3245 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3246 DWORD i;
3247 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3252 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3253 int i = This->rev_tex_unit_map[unit];
3254 int j = This->texUnitMap[stage];
3256 This->texUnitMap[stage] = unit;
3257 if (i != -1 && i != stage) {
3258 This->texUnitMap[i] = -1;
3261 This->rev_tex_unit_map[unit] = stage;
3262 if (j != -1 && j != unit) {
3263 This->rev_tex_unit_map[j] = -1;
3267 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3268 int i;
3270 for (i = 0; i < MAX_TEXTURES; ++i) {
3271 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3272 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3273 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3274 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3275 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3276 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3277 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3278 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3280 if (color_op == WINED3DTOP_DISABLE) {
3281 /* Not used, and disable higher stages */
3282 while (i < MAX_TEXTURES) {
3283 This->fixed_function_usage_map[i] = FALSE;
3284 ++i;
3286 break;
3289 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3290 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3291 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3292 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3293 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3294 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3295 This->fixed_function_usage_map[i] = TRUE;
3296 } else {
3297 This->fixed_function_usage_map[i] = FALSE;
3300 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3301 This->fixed_function_usage_map[i+1] = TRUE;
3306 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3307 int i, tex;
3309 device_update_fixed_function_usage_map(This);
3311 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3312 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3313 if (!This->fixed_function_usage_map[i]) continue;
3315 if (This->texUnitMap[i] != i) {
3316 device_map_stage(This, i, i);
3317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3318 markTextureStagesDirty(This, i);
3321 return;
3324 /* Now work out the mapping */
3325 tex = 0;
3326 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3327 if (!This->fixed_function_usage_map[i]) continue;
3329 if (This->texUnitMap[i] != tex) {
3330 device_map_stage(This, i, tex);
3331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3332 markTextureStagesDirty(This, i);
3335 ++tex;
3339 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3340 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3341 int i;
3343 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3344 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3345 device_map_stage(This, i, i);
3346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3347 if (i < MAX_TEXTURES) {
3348 markTextureStagesDirty(This, i);
3354 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3355 int current_mapping = This->rev_tex_unit_map[unit];
3357 if (current_mapping == -1) {
3358 /* Not currently used */
3359 return TRUE;
3362 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3363 /* Used by a fragment sampler */
3365 if (!pshader_sampler_tokens) {
3366 /* No pixel shader, check fixed function */
3367 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3370 /* Pixel shader, check the shader's sampler map */
3371 return !pshader_sampler_tokens[current_mapping];
3374 /* Used by a vertex sampler */
3375 return !vshader_sampler_tokens[current_mapping];
3378 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3379 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3380 DWORD *pshader_sampler_tokens = NULL;
3381 int start = GL_LIMITS(combined_samplers) - 1;
3382 int i;
3384 if (ps) {
3385 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3387 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3388 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3389 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3392 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3393 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3394 if (vshader_sampler_tokens[i]) {
3395 if (This->texUnitMap[vsampler_idx] != -1) {
3396 /* Already mapped somewhere */
3397 continue;
3400 while (start >= 0) {
3401 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3402 device_map_stage(This, vsampler_idx, start);
3403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3405 --start;
3406 break;
3409 --start;
3415 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3416 BOOL vs = use_vs(This);
3417 BOOL ps = use_ps(This);
3419 * Rules are:
3420 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3421 * that would be really messy and require shader recompilation
3422 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3423 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3425 if (ps) {
3426 device_map_psamplers(This);
3427 } else {
3428 device_map_fixed_function_samplers(This);
3431 if (vs) {
3432 device_map_vsamplers(This, ps);
3436 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3437 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3438 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3439 This->updateStateBlock->pixelShader = pShader;
3440 This->updateStateBlock->changed.pixelShader = TRUE;
3442 /* Handle recording of state blocks */
3443 if (This->isRecordingState) {
3444 TRACE("Recording... not performing anything\n");
3447 if (This->isRecordingState) {
3448 TRACE("Recording... not performing anything\n");
3449 return WINED3D_OK;
3452 if(pShader == oldShader) {
3453 TRACE("App is setting the old pixel shader over, nothing to do\n");
3454 return WINED3D_OK;
3457 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3458 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3460 return WINED3D_OK;
3463 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 if (NULL == ppShader) {
3467 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3468 return WINED3DERR_INVALIDCALL;
3471 *ppShader = This->stateBlock->pixelShader;
3472 if (NULL != *ppShader) {
3473 IWineD3DPixelShader_AddRef(*ppShader);
3475 TRACE("(%p) : returning %p\n", This, *ppShader);
3476 return WINED3D_OK;
3479 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3480 IWineD3DDevice *iface,
3481 UINT start,
3482 CONST BOOL *srcData,
3483 UINT count) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3486 int i, cnt = min(count, MAX_CONST_B - start);
3488 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3489 iface, srcData, start, count);
3491 if (srcData == NULL || cnt < 0)
3492 return WINED3DERR_INVALIDCALL;
3494 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3495 for (i = 0; i < cnt; i++)
3496 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3498 for (i = start; i < cnt + start; ++i) {
3499 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3504 return WINED3D_OK;
3507 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3508 IWineD3DDevice *iface,
3509 UINT start,
3510 BOOL *dstData,
3511 UINT count) {
3513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3514 int cnt = min(count, MAX_CONST_B - start);
3516 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3517 iface, dstData, start, count);
3519 if (dstData == NULL || cnt < 0)
3520 return WINED3DERR_INVALIDCALL;
3522 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3523 return WINED3D_OK;
3526 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3527 IWineD3DDevice *iface,
3528 UINT start,
3529 CONST int *srcData,
3530 UINT count) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 int i, cnt = min(count, MAX_CONST_I - start);
3535 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3536 iface, srcData, start, count);
3538 if (srcData == NULL || cnt < 0)
3539 return WINED3DERR_INVALIDCALL;
3541 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3542 for (i = 0; i < cnt; i++)
3543 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3544 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3546 for (i = start; i < cnt + start; ++i) {
3547 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3550 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3552 return WINED3D_OK;
3555 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3556 IWineD3DDevice *iface,
3557 UINT start,
3558 int *dstData,
3559 UINT count) {
3561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3562 int cnt = min(count, MAX_CONST_I - start);
3564 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3565 iface, dstData, start, count);
3567 if (dstData == NULL || cnt < 0)
3568 return WINED3DERR_INVALIDCALL;
3570 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3571 return WINED3D_OK;
3574 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3575 IWineD3DDevice *iface,
3576 UINT start,
3577 CONST float *srcData,
3578 UINT count) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 int i;
3583 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3584 iface, srcData, start, count);
3586 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3587 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3588 return WINED3DERR_INVALIDCALL;
3590 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3591 if(TRACE_ON(d3d)) {
3592 for (i = 0; i < count; i++)
3593 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3594 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3597 for (i = start; i < count + start; ++i) {
3598 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3599 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3600 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3601 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3602 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3604 ptr->idx[ptr->count++] = i;
3605 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3611 return WINED3D_OK;
3614 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3615 IWineD3DDevice *iface,
3616 UINT start,
3617 float *dstData,
3618 UINT count) {
3620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3621 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3623 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3624 iface, dstData, start, count);
3626 if (dstData == NULL || cnt < 0)
3627 return WINED3DERR_INVALIDCALL;
3629 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3630 return WINED3D_OK;
3633 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3634 static HRESULT
3635 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3636 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3637 unsigned int i;
3638 DWORD DestFVF = dest->fvf;
3639 WINED3DVIEWPORT vp;
3640 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3641 BOOL doClip;
3642 int numTextures;
3644 if (lpStrideData->u.s.normal.lpData) {
3645 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3648 if (lpStrideData->u.s.position.lpData == NULL) {
3649 ERR("Source has no position mask\n");
3650 return WINED3DERR_INVALIDCALL;
3653 /* We might access VBOs from this code, so hold the lock */
3654 ENTER_GL();
3656 if (dest->resource.allocatedMemory == NULL) {
3657 /* This may happen if we do direct locking into a vbo. Unlikely,
3658 * but theoretically possible(ddraw processvertices test)
3660 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3661 if(!dest->resource.allocatedMemory) {
3662 LEAVE_GL();
3663 ERR("Out of memory\n");
3664 return E_OUTOFMEMORY;
3666 if(dest->vbo) {
3667 void *src;
3668 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3669 checkGLcall("glBindBufferARB");
3670 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3671 if(src) {
3672 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3674 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3675 checkGLcall("glUnmapBufferARB");
3679 /* Get a pointer into the destination vbo(create one if none exists) and
3680 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3682 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3683 CreateVBO(dest);
3686 if(dest->vbo) {
3687 unsigned char extrabytes = 0;
3688 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3689 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3690 * this may write 4 extra bytes beyond the area that should be written
3692 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3693 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3694 if(!dest_conv_addr) {
3695 ERR("Out of memory\n");
3696 /* Continue without storing converted vertices */
3698 dest_conv = dest_conv_addr;
3701 /* Should I clip?
3702 * a) WINED3DRS_CLIPPING is enabled
3703 * b) WINED3DVOP_CLIP is passed
3705 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3706 static BOOL warned = FALSE;
3708 * The clipping code is not quite correct. Some things need
3709 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3710 * so disable clipping for now.
3711 * (The graphics in Half-Life are broken, and my processvertices
3712 * test crashes with IDirect3DDevice3)
3713 doClip = TRUE;
3715 doClip = FALSE;
3716 if(!warned) {
3717 warned = TRUE;
3718 FIXME("Clipping is broken and disabled for now\n");
3720 } else doClip = FALSE;
3721 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3723 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3724 WINED3DTS_VIEW,
3725 &view_mat);
3726 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3727 WINED3DTS_PROJECTION,
3728 &proj_mat);
3729 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3730 WINED3DTS_WORLDMATRIX(0),
3731 &world_mat);
3733 TRACE("View mat:\n");
3734 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);
3735 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);
3736 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);
3737 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);
3739 TRACE("Proj mat:\n");
3740 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);
3741 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);
3742 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);
3743 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);
3745 TRACE("World mat:\n");
3746 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);
3747 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);
3748 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);
3749 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);
3751 /* Get the viewport */
3752 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3753 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3754 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3756 multiply_matrix(&mat,&view_mat,&world_mat);
3757 multiply_matrix(&mat,&proj_mat,&mat);
3759 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3761 for (i = 0; i < dwCount; i+= 1) {
3762 unsigned int tex_index;
3764 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3765 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3766 /* The position first */
3767 float *p =
3768 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3769 float x, y, z, rhw;
3770 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3772 /* Multiplication with world, view and projection matrix */
3773 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);
3774 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);
3775 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);
3776 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);
3778 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3780 /* WARNING: The following things are taken from d3d7 and were not yet checked
3781 * against d3d8 or d3d9!
3784 /* Clipping conditions: From
3785 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3787 * A vertex is clipped if it does not match the following requirements
3788 * -rhw < x <= rhw
3789 * -rhw < y <= rhw
3790 * 0 < z <= rhw
3791 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3793 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3794 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3798 if( !doClip ||
3799 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3800 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3801 ( rhw > eps ) ) ) {
3803 /* "Normal" viewport transformation (not clipped)
3804 * 1) The values are divided by rhw
3805 * 2) The y axis is negative, so multiply it with -1
3806 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3807 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3808 * 4) Multiply x with Width/2 and add Width/2
3809 * 5) The same for the height
3810 * 6) Add the viewpoint X and Y to the 2D coordinates and
3811 * The minimum Z value to z
3812 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3814 * Well, basically it's simply a linear transformation into viewport
3815 * coordinates
3818 x /= rhw;
3819 y /= rhw;
3820 z /= rhw;
3822 y *= -1;
3824 x *= vp.Width / 2;
3825 y *= vp.Height / 2;
3826 z *= vp.MaxZ - vp.MinZ;
3828 x += vp.Width / 2 + vp.X;
3829 y += vp.Height / 2 + vp.Y;
3830 z += vp.MinZ;
3832 rhw = 1 / rhw;
3833 } else {
3834 /* That vertex got clipped
3835 * Contrary to OpenGL it is not dropped completely, it just
3836 * undergoes a different calculation.
3838 TRACE("Vertex got clipped\n");
3839 x += rhw;
3840 y += rhw;
3842 x /= 2;
3843 y /= 2;
3845 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3846 * outside of the main vertex buffer memory. That needs some more
3847 * investigation...
3851 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3854 ( (float *) dest_ptr)[0] = x;
3855 ( (float *) dest_ptr)[1] = y;
3856 ( (float *) dest_ptr)[2] = z;
3857 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3859 dest_ptr += 3 * sizeof(float);
3861 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3862 dest_ptr += sizeof(float);
3865 if(dest_conv) {
3866 float w = 1 / rhw;
3867 ( (float *) dest_conv)[0] = x * w;
3868 ( (float *) dest_conv)[1] = y * w;
3869 ( (float *) dest_conv)[2] = z * w;
3870 ( (float *) dest_conv)[3] = w;
3872 dest_conv += 3 * sizeof(float);
3874 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3875 dest_conv += sizeof(float);
3879 if (DestFVF & WINED3DFVF_PSIZE) {
3880 dest_ptr += sizeof(DWORD);
3881 if(dest_conv) dest_conv += sizeof(DWORD);
3883 if (DestFVF & WINED3DFVF_NORMAL) {
3884 float *normal =
3885 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3886 /* AFAIK this should go into the lighting information */
3887 FIXME("Didn't expect the destination to have a normal\n");
3888 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3889 if(dest_conv) {
3890 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3894 if (DestFVF & WINED3DFVF_DIFFUSE) {
3895 DWORD *color_d =
3896 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3897 if(!color_d) {
3898 static BOOL warned = FALSE;
3900 if(!warned) {
3901 ERR("No diffuse color in source, but destination has one\n");
3902 warned = TRUE;
3905 *( (DWORD *) dest_ptr) = 0xffffffff;
3906 dest_ptr += sizeof(DWORD);
3908 if(dest_conv) {
3909 *( (DWORD *) dest_conv) = 0xffffffff;
3910 dest_conv += sizeof(DWORD);
3913 else {
3914 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3915 if(dest_conv) {
3916 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3917 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3918 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3919 dest_conv += sizeof(DWORD);
3924 if (DestFVF & WINED3DFVF_SPECULAR) {
3925 /* What's the color value in the feedback buffer? */
3926 DWORD *color_s =
3927 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3928 if(!color_s) {
3929 static BOOL warned = FALSE;
3931 if(!warned) {
3932 ERR("No specular color in source, but destination has one\n");
3933 warned = TRUE;
3936 *( (DWORD *) dest_ptr) = 0xFF000000;
3937 dest_ptr += sizeof(DWORD);
3939 if(dest_conv) {
3940 *( (DWORD *) dest_conv) = 0xFF000000;
3941 dest_conv += sizeof(DWORD);
3944 else {
3945 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3946 if(dest_conv) {
3947 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3948 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3949 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3950 dest_conv += sizeof(DWORD);
3955 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3956 float *tex_coord =
3957 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3958 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3959 if(!tex_coord) {
3960 ERR("No source texture, but destination requests one\n");
3961 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3962 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3964 else {
3965 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3966 if(dest_conv) {
3967 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3973 if(dest_conv) {
3974 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3975 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3976 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3977 dwCount * get_flexible_vertex_size(DestFVF),
3978 dest_conv_addr));
3979 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3980 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3983 LEAVE_GL();
3985 return WINED3D_OK;
3987 #undef copy_and_next
3989 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 WineDirect3DVertexStridedData strided;
3992 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3993 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3995 if(pVertexDecl) {
3996 ERR("Output vertex declaration not implemented yet\n");
3999 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4000 * and this call is quite performance critical, so don't call needlessly
4002 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4003 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4006 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4007 * control the streamIsUP flag, thus restore it afterwards.
4009 This->stateBlock->streamIsUP = FALSE;
4010 memset(&strided, 0, sizeof(strided));
4011 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4012 This->stateBlock->streamIsUP = streamWasUP;
4014 if(vbo || SrcStartIndex) {
4015 unsigned int i;
4016 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4017 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4019 * Also get the start index in, but only loop over all elements if there's something to add at all.
4021 #define FIXSRC(type) \
4022 if(strided.u.s.type.VBO) { \
4023 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4024 strided.u.s.type.VBO = 0; \
4025 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4026 ENTER_GL(); \
4027 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4028 vb->vbo = 0; \
4029 LEAVE_GL(); \
4031 if(strided.u.s.type.lpData) { \
4032 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4034 FIXSRC(position);
4035 FIXSRC(blendWeights);
4036 FIXSRC(blendMatrixIndices);
4037 FIXSRC(normal);
4038 FIXSRC(pSize);
4039 FIXSRC(diffuse);
4040 FIXSRC(specular);
4041 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4042 FIXSRC(texCoords[i]);
4044 FIXSRC(position2);
4045 FIXSRC(normal2);
4046 FIXSRC(tangent);
4047 FIXSRC(binormal);
4048 FIXSRC(tessFactor);
4049 FIXSRC(fog);
4050 FIXSRC(depth);
4051 FIXSRC(sample);
4052 #undef FIXSRC
4055 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4058 /*****
4059 * Get / Set Texture Stage States
4060 * TODO: Verify against dx9 definitions
4061 *****/
4062 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4064 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4066 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4068 if (Stage >= MAX_TEXTURES) {
4069 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4070 return WINED3D_OK;
4073 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4074 This->updateStateBlock->textureState[Stage][Type] = Value;
4076 if (This->isRecordingState) {
4077 TRACE("Recording... not performing anything\n");
4078 return WINED3D_OK;
4081 /* Checked after the assignments to allow proper stateblock recording */
4082 if(oldValue == Value) {
4083 TRACE("App is setting the old value over, nothing to do\n");
4084 return WINED3D_OK;
4087 if(Stage > This->stateBlock->lowest_disabled_stage &&
4088 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4089 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4090 * Changes in other states are important on disabled stages too
4092 return WINED3D_OK;
4095 if(Type == WINED3DTSS_COLOROP) {
4096 int i;
4098 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4099 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4100 * they have to be disabled
4102 * The current stage is dirtified below.
4104 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4105 TRACE("Additionally dirtifying stage %d\n", i);
4106 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4108 This->stateBlock->lowest_disabled_stage = Stage;
4109 TRACE("New lowest disabled: %d\n", Stage);
4110 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4111 /* Previously disabled stage enabled. Stages above it may need enabling
4112 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4113 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4115 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4118 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4119 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4120 break;
4122 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4125 This->stateBlock->lowest_disabled_stage = i;
4126 TRACE("New lowest disabled: %d\n", i);
4128 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4129 /* TODO: Built a stage -> texture unit mapping for register combiners */
4133 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4135 return WINED3D_OK;
4138 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4140 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4141 *pValue = This->updateStateBlock->textureState[Stage][Type];
4142 return WINED3D_OK;
4145 /*****
4146 * Get / Set Texture
4147 *****/
4148 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4150 IWineD3DBaseTexture *oldTexture;
4152 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4154 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4155 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4158 oldTexture = This->updateStateBlock->textures[Stage];
4160 if(pTexture != NULL) {
4161 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4163 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4164 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4165 return WINED3DERR_INVALIDCALL;
4167 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4170 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4171 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4173 This->updateStateBlock->changed.textures[Stage] = TRUE;
4174 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4175 This->updateStateBlock->textures[Stage] = pTexture;
4177 /* Handle recording of state blocks */
4178 if (This->isRecordingState) {
4179 TRACE("Recording... not performing anything\n");
4180 return WINED3D_OK;
4183 if(oldTexture == pTexture) {
4184 TRACE("App is setting the same texture again, nothing to do\n");
4185 return WINED3D_OK;
4188 /** NOTE: MSDN says that setTexture increases the reference count,
4189 * and the the application must set the texture back to null (or have a leaky application),
4190 * This means we should pass the refcount up to the parent
4191 *******************************/
4192 if (NULL != This->updateStateBlock->textures[Stage]) {
4193 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4194 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4196 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4197 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4198 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4199 * so the COLOROP and ALPHAOP have to be dirtified.
4201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4204 if(bindCount == 1) {
4205 new->baseTexture.sampler = Stage;
4207 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4211 if (NULL != oldTexture) {
4212 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4213 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4215 IWineD3DBaseTexture_Release(oldTexture);
4216 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4221 if(bindCount && old->baseTexture.sampler == Stage) {
4222 int i;
4223 /* Have to do a search for the other sampler(s) where the texture is bound to
4224 * Shouldn't happen as long as apps bind a texture only to one stage
4226 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4227 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4228 if(This->updateStateBlock->textures[i] == oldTexture) {
4229 old->baseTexture.sampler = i;
4230 break;
4236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4238 return WINED3D_OK;
4241 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4244 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4246 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4247 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4250 *ppTexture=This->stateBlock->textures[Stage];
4251 if (*ppTexture)
4252 IWineD3DBaseTexture_AddRef(*ppTexture);
4254 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4256 return WINED3D_OK;
4259 /*****
4260 * Get Back Buffer
4261 *****/
4262 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4263 IWineD3DSurface **ppBackBuffer) {
4264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4265 IWineD3DSwapChain *swapChain;
4266 HRESULT hr;
4268 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4270 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4271 if (hr == WINED3D_OK) {
4272 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4273 IWineD3DSwapChain_Release(swapChain);
4274 } else {
4275 *ppBackBuffer = NULL;
4277 return hr;
4280 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4282 WARN("(%p) : stub, calling idirect3d for now\n", This);
4283 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4286 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4288 IWineD3DSwapChain *swapChain;
4289 HRESULT hr;
4291 if(iSwapChain > 0) {
4292 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4293 if (hr == WINED3D_OK) {
4294 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4295 IWineD3DSwapChain_Release(swapChain);
4296 } else {
4297 FIXME("(%p) Error getting display mode\n", This);
4299 } else {
4300 /* Don't read the real display mode,
4301 but return the stored mode instead. X11 can't change the color
4302 depth, and some apps are pretty angry if they SetDisplayMode from
4303 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4305 Also don't relay to the swapchain because with ddraw it's possible
4306 that there isn't a swapchain at all */
4307 pMode->Width = This->ddraw_width;
4308 pMode->Height = This->ddraw_height;
4309 pMode->Format = This->ddraw_format;
4310 pMode->RefreshRate = 0;
4311 hr = WINED3D_OK;
4314 return hr;
4317 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4319 TRACE("(%p)->(%p)\n", This, hWnd);
4321 if(This->ddraw_fullscreen) {
4322 if(This->ddraw_window && This->ddraw_window != hWnd) {
4323 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4325 if(hWnd && This->ddraw_window != hWnd) {
4326 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4330 This->ddraw_window = hWnd;
4331 return WINED3D_OK;
4334 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4336 TRACE("(%p)->(%p)\n", This, hWnd);
4338 *hWnd = This->ddraw_window;
4339 return WINED3D_OK;
4342 /*****
4343 * Stateblock related functions
4344 *****/
4346 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4347 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4348 IWineD3DStateBlockImpl *object;
4349 HRESULT temp_result;
4350 int i;
4352 TRACE("(%p)\n", This);
4354 if (This->isRecordingState) {
4355 return WINED3DERR_INVALIDCALL;
4358 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4359 if (NULL == object ) {
4360 FIXME("(%p)Error allocating memory for stateblock\n", This);
4361 return E_OUTOFMEMORY;
4363 TRACE("(%p) created object %p\n", This, object);
4364 object->wineD3DDevice= This;
4365 /** FIXME: object->parent = parent; **/
4366 object->parent = NULL;
4367 object->blockType = WINED3DSBT_RECORDED;
4368 object->ref = 1;
4369 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4371 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4372 list_init(&object->lightMap[i]);
4375 temp_result = allocate_shader_constants(object);
4376 if (WINED3D_OK != temp_result)
4377 return temp_result;
4379 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4380 This->updateStateBlock = object;
4381 This->isRecordingState = TRUE;
4383 TRACE("(%p) recording stateblock %p\n",This , object);
4384 return WINED3D_OK;
4387 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4389 unsigned int i, j;
4390 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4392 if (!This->isRecordingState) {
4393 FIXME("(%p) not recording! returning error\n", This);
4394 *ppStateBlock = NULL;
4395 return WINED3DERR_INVALIDCALL;
4398 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4399 if(object->changed.renderState[i]) {
4400 object->contained_render_states[object->num_contained_render_states] = i;
4401 object->num_contained_render_states++;
4404 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4405 if(object->changed.transform[i]) {
4406 object->contained_transform_states[object->num_contained_transform_states] = i;
4407 object->num_contained_transform_states++;
4410 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4411 if(object->changed.vertexShaderConstantsF[i]) {
4412 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4413 object->num_contained_vs_consts_f++;
4416 for(i = 0; i < MAX_CONST_I; i++) {
4417 if(object->changed.vertexShaderConstantsI[i]) {
4418 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4419 object->num_contained_vs_consts_i++;
4422 for(i = 0; i < MAX_CONST_B; i++) {
4423 if(object->changed.vertexShaderConstantsB[i]) {
4424 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4425 object->num_contained_vs_consts_b++;
4428 for(i = 0; i < MAX_CONST_I; i++) {
4429 if(object->changed.pixelShaderConstantsI[i]) {
4430 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4431 object->num_contained_ps_consts_i++;
4434 for(i = 0; i < MAX_CONST_B; i++) {
4435 if(object->changed.pixelShaderConstantsB[i]) {
4436 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4437 object->num_contained_ps_consts_b++;
4440 for(i = 0; i < MAX_TEXTURES; i++) {
4441 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4442 if(object->changed.textureState[i][j]) {
4443 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4444 object->contained_tss_states[object->num_contained_tss_states].state = j;
4445 object->num_contained_tss_states++;
4449 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4450 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4451 if(object->changed.samplerState[i][j]) {
4452 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4453 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4454 object->num_contained_sampler_states++;
4459 *ppStateBlock = (IWineD3DStateBlock*) object;
4460 This->isRecordingState = FALSE;
4461 This->updateStateBlock = This->stateBlock;
4462 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4463 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4464 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4465 return WINED3D_OK;
4468 /*****
4469 * Scene related functions
4470 *****/
4471 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4472 /* At the moment we have no need for any functionality at the beginning
4473 of a scene */
4474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4475 TRACE("(%p)\n", This);
4477 if(This->inScene) {
4478 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4479 return WINED3DERR_INVALIDCALL;
4481 This->inScene = TRUE;
4482 return WINED3D_OK;
4485 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 TRACE("(%p)\n", This);
4489 if(!This->inScene) {
4490 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4491 return WINED3DERR_INVALIDCALL;
4494 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4495 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4497 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4498 ENTER_GL();
4499 glFlush();
4500 checkGLcall("glFlush");
4501 LEAVE_GL();
4503 This->inScene = FALSE;
4504 return WINED3D_OK;
4507 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4508 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4509 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4510 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4511 IWineD3DSwapChain *swapChain = NULL;
4512 int i;
4513 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4515 TRACE("(%p) Presenting the frame\n", This);
4517 for(i = 0 ; i < swapchains ; i ++) {
4519 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4520 TRACE("presentinng chain %d, %p\n", i, swapChain);
4521 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4522 IWineD3DSwapChain_Release(swapChain);
4525 return WINED3D_OK;
4528 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4529 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4531 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4533 GLbitfield glMask = 0;
4534 unsigned int i;
4535 CONST WINED3DRECT* curRect;
4537 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4538 Count, pRects, Flags, Color, Z, Stencil);
4540 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4541 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4542 /* TODO: What about depth stencil buffers without stencil bits? */
4543 return WINED3DERR_INVALIDCALL;
4546 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4547 * and not the last active one.
4549 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4550 ENTER_GL();
4552 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4553 apply_fbo_state(iface);
4556 if (Count > 0 && pRects) {
4557 curRect = pRects;
4558 } else {
4559 curRect = NULL;
4562 /* Only set the values up once, as they are not changing */
4563 if (Flags & WINED3DCLEAR_STENCIL) {
4564 glClearStencil(Stencil);
4565 checkGLcall("glClearStencil");
4566 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4567 glStencilMask(0xFFFFFFFF);
4570 if (Flags & WINED3DCLEAR_ZBUFFER) {
4571 glDepthMask(GL_TRUE);
4572 glClearDepth(Z);
4573 checkGLcall("glClearDepth");
4574 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4578 if (Flags & WINED3DCLEAR_TARGET) {
4579 TRACE("Clearing screen with glClear to color %x\n", Color);
4580 glClearColor(D3DCOLOR_R(Color),
4581 D3DCOLOR_G(Color),
4582 D3DCOLOR_B(Color),
4583 D3DCOLOR_A(Color));
4584 checkGLcall("glClearColor");
4586 /* Clear ALL colors! */
4587 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4588 glMask = glMask | GL_COLOR_BUFFER_BIT;
4591 if (!curRect) {
4592 /* In drawable flag is set below */
4594 if (This->render_offscreen) {
4595 glScissor(This->stateBlock->viewport.X,
4596 This->stateBlock->viewport.Y,
4597 This->stateBlock->viewport.Width,
4598 This->stateBlock->viewport.Height);
4599 } else {
4600 glScissor(This->stateBlock->viewport.X,
4601 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4602 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4603 This->stateBlock->viewport.Width,
4604 This->stateBlock->viewport.Height);
4606 checkGLcall("glScissor");
4607 glClear(glMask);
4608 checkGLcall("glClear");
4609 } else {
4610 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4611 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4613 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4614 curRect[0].x2 < target->currentDesc.Width ||
4615 curRect[0].y2 < target->currentDesc.Height) {
4616 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4617 blt_to_drawable(This, target);
4621 /* Now process each rect in turn */
4622 for (i = 0; i < Count; i++) {
4623 /* Note gl uses lower left, width/height */
4624 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4625 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4626 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4627 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4629 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4630 * The rectangle is not cleared, no error is returned, but further rectanlges are
4631 * still cleared if they are valid
4633 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4634 TRACE("Rectangle with negative dimensions, ignoring\n");
4635 continue;
4638 if(This->render_offscreen) {
4639 glScissor(curRect[i].x1, curRect[i].y1,
4640 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4641 } else {
4642 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4643 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4645 checkGLcall("glScissor");
4647 glClear(glMask);
4648 checkGLcall("glClear");
4652 /* Restore the old values (why..?) */
4653 if (Flags & WINED3DCLEAR_STENCIL) {
4654 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4656 if (Flags & WINED3DCLEAR_TARGET) {
4657 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4658 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4659 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4660 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4661 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4664 LEAVE_GL();
4666 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4667 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4669 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4670 target->Flags |= SFLAG_INTEXTURE;
4671 target->Flags &= ~SFLAG_INSYSMEM;
4672 } else {
4673 target->Flags |= SFLAG_INDRAWABLE;
4674 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4676 return WINED3D_OK;
4679 /*****
4680 * Drawing functions
4681 *****/
4682 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4683 UINT PrimitiveCount) {
4685 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4687 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4688 debug_d3dprimitivetype(PrimitiveType),
4689 StartVertex, PrimitiveCount);
4691 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4692 if(This->stateBlock->streamIsUP) {
4693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4694 This->stateBlock->streamIsUP = FALSE;
4697 if(This->stateBlock->loadBaseVertexIndex != 0) {
4698 This->stateBlock->loadBaseVertexIndex = 0;
4699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4701 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4702 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4703 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4704 return WINED3D_OK;
4707 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4708 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4709 WINED3DPRIMITIVETYPE PrimitiveType,
4710 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 UINT idxStride = 2;
4714 IWineD3DIndexBuffer *pIB;
4715 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4716 GLuint vbo;
4718 pIB = This->stateBlock->pIndexData;
4719 if (!pIB) {
4720 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4721 * without an index buffer set. (The first time at least...)
4722 * D3D8 simply dies, but I doubt it can do much harm to return
4723 * D3DERR_INVALIDCALL there as well. */
4724 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4725 return WINED3DERR_INVALIDCALL;
4728 if(This->stateBlock->streamIsUP) {
4729 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4730 This->stateBlock->streamIsUP = FALSE;
4732 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4734 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4735 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4736 minIndex, NumVertices, startIndex, primCount);
4738 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4739 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4740 idxStride = 2;
4741 } else {
4742 idxStride = 4;
4745 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4746 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4750 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4751 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4753 return WINED3D_OK;
4756 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4757 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4758 UINT VertexStreamZeroStride) {
4759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 IWineD3DVertexBuffer *vb;
4762 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4763 debug_d3dprimitivetype(PrimitiveType),
4764 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4766 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4767 vb = This->stateBlock->streamSource[0];
4768 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4769 if(vb) IWineD3DVertexBuffer_Release(vb);
4770 This->stateBlock->streamOffset[0] = 0;
4771 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4772 This->stateBlock->streamIsUP = TRUE;
4773 This->stateBlock->loadBaseVertexIndex = 0;
4775 /* TODO: Only mark dirty if drawing from a different UP address */
4776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4778 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4779 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4781 /* MSDN specifies stream zero settings must be set to NULL */
4782 This->stateBlock->streamStride[0] = 0;
4783 This->stateBlock->streamSource[0] = NULL;
4785 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4786 * the new stream sources or use UP drawing again
4788 return WINED3D_OK;
4791 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4792 UINT MinVertexIndex, UINT NumVertices,
4793 UINT PrimitiveCount, CONST void* pIndexData,
4794 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4795 UINT VertexStreamZeroStride) {
4796 int idxStride;
4797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4798 IWineD3DVertexBuffer *vb;
4799 IWineD3DIndexBuffer *ib;
4801 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4802 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4803 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4804 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4806 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4807 idxStride = 2;
4808 } else {
4809 idxStride = 4;
4812 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4813 vb = This->stateBlock->streamSource[0];
4814 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4815 if(vb) IWineD3DVertexBuffer_Release(vb);
4816 This->stateBlock->streamIsUP = TRUE;
4817 This->stateBlock->streamOffset[0] = 0;
4818 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4820 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4821 This->stateBlock->baseVertexIndex = 0;
4822 This->stateBlock->loadBaseVertexIndex = 0;
4823 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4824 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4825 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4827 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4829 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4830 This->stateBlock->streamSource[0] = NULL;
4831 This->stateBlock->streamStride[0] = 0;
4832 ib = This->stateBlock->pIndexData;
4833 if(ib) {
4834 IWineD3DIndexBuffer_Release(ib);
4835 This->stateBlock->pIndexData = NULL;
4837 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4838 * SetStreamSource to specify a vertex buffer
4841 return WINED3D_OK;
4844 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4845 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4847 /* Mark the state dirty until we have nicer tracking
4848 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4849 * that value.
4851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4853 This->stateBlock->baseVertexIndex = 0;
4854 This->up_strided = DrawPrimStrideData;
4855 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4856 This->up_strided = NULL;
4857 return WINED3D_OK;
4860 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4862 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4864 /* Mark the state dirty until we have nicer tracking
4865 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4866 * that value.
4868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4870 This->stateBlock->streamIsUP = TRUE;
4871 This->stateBlock->baseVertexIndex = 0;
4872 This->up_strided = DrawPrimStrideData;
4873 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4874 This->up_strided = NULL;
4875 return WINED3D_OK;
4879 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4880 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 HRESULT hr = WINED3D_OK;
4883 WINED3DRESOURCETYPE sourceType;
4884 WINED3DRESOURCETYPE destinationType;
4885 int i ,levels;
4887 /* TODO: think about moving the code into IWineD3DBaseTexture */
4889 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4891 /* verify that the source and destination textures aren't NULL */
4892 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4893 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4894 This, pSourceTexture, pDestinationTexture);
4895 hr = WINED3DERR_INVALIDCALL;
4898 if (pSourceTexture == pDestinationTexture) {
4899 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4900 This, pSourceTexture, pDestinationTexture);
4901 hr = WINED3DERR_INVALIDCALL;
4903 /* Verify that the source and destination textures are the same type */
4904 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4905 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4907 if (sourceType != destinationType) {
4908 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4909 This);
4910 hr = WINED3DERR_INVALIDCALL;
4913 /* check that both textures have the identical numbers of levels */
4914 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4915 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4916 hr = WINED3DERR_INVALIDCALL;
4919 if (WINED3D_OK == hr) {
4921 /* Make sure that the destination texture is loaded */
4922 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4924 /* Update every surface level of the texture */
4925 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4927 switch (sourceType) {
4928 case WINED3DRTYPE_TEXTURE:
4930 IWineD3DSurface *srcSurface;
4931 IWineD3DSurface *destSurface;
4933 for (i = 0 ; i < levels ; ++i) {
4934 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4935 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4936 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4937 IWineD3DSurface_Release(srcSurface);
4938 IWineD3DSurface_Release(destSurface);
4939 if (WINED3D_OK != hr) {
4940 WARN("(%p) : Call to update surface failed\n", This);
4941 return hr;
4945 break;
4946 case WINED3DRTYPE_CUBETEXTURE:
4948 IWineD3DSurface *srcSurface;
4949 IWineD3DSurface *destSurface;
4950 WINED3DCUBEMAP_FACES faceType;
4952 for (i = 0 ; i < levels ; ++i) {
4953 /* Update each cube face */
4954 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4955 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4956 if (WINED3D_OK != hr) {
4957 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4958 } else {
4959 TRACE("Got srcSurface %p\n", srcSurface);
4961 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4962 if (WINED3D_OK != hr) {
4963 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4964 } else {
4965 TRACE("Got desrSurface %p\n", destSurface);
4967 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4968 IWineD3DSurface_Release(srcSurface);
4969 IWineD3DSurface_Release(destSurface);
4970 if (WINED3D_OK != hr) {
4971 WARN("(%p) : Call to update surface failed\n", This);
4972 return hr;
4977 break;
4978 #if 0 /* TODO: Add support for volume textures */
4979 case WINED3DRTYPE_VOLUMETEXTURE:
4981 IWineD3DVolume srcVolume = NULL;
4982 IWineD3DSurface destVolume = NULL;
4984 for (i = 0 ; i < levels ; ++i) {
4985 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4986 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4987 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4988 IWineD3DVolume_Release(srcSurface);
4989 IWineD3DVolume_Release(destSurface);
4990 if (WINED3D_OK != hr) {
4991 WARN("(%p) : Call to update volume failed\n", This);
4992 return hr;
4996 break;
4997 #endif
4998 default:
4999 FIXME("(%p) : Unsupported source and destination type\n", This);
5000 hr = WINED3DERR_INVALIDCALL;
5004 return hr;
5007 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5008 IWineD3DSwapChain *swapChain;
5009 HRESULT hr;
5010 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5011 if(hr == WINED3D_OK) {
5012 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5013 IWineD3DSwapChain_Release(swapChain);
5015 return hr;
5018 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5020 /* return a sensible default */
5021 *pNumPasses = 1;
5022 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5023 FIXME("(%p) : stub\n", This);
5024 return WINED3D_OK;
5027 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5029 int j;
5030 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5031 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5032 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5033 return WINED3DERR_INVALIDCALL;
5035 for (j = 0; j < 256; ++j) {
5036 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5037 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5038 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5039 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5041 TRACE("(%p) : returning\n", This);
5042 return WINED3D_OK;
5045 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5047 int j;
5048 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5049 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5050 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5051 return WINED3DERR_INVALIDCALL;
5053 for (j = 0; j < 256; ++j) {
5054 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5055 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5056 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5057 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5059 TRACE("(%p) : returning\n", This);
5060 return WINED3D_OK;
5063 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5065 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5066 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5067 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5068 return WINED3DERR_INVALIDCALL;
5070 /*TODO: stateblocks */
5071 This->currentPalette = PaletteNumber;
5072 TRACE("(%p) : returning\n", This);
5073 return WINED3D_OK;
5076 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5078 if (PaletteNumber == NULL) {
5079 WARN("(%p) : returning Invalid Call\n", This);
5080 return WINED3DERR_INVALIDCALL;
5082 /*TODO: stateblocks */
5083 *PaletteNumber = This->currentPalette;
5084 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5085 return WINED3D_OK;
5088 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5090 static BOOL showFixmes = TRUE;
5091 if (showFixmes) {
5092 FIXME("(%p) : stub\n", This);
5093 showFixmes = FALSE;
5096 This->softwareVertexProcessing = bSoftware;
5097 return WINED3D_OK;
5101 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5103 static BOOL showFixmes = TRUE;
5104 if (showFixmes) {
5105 FIXME("(%p) : stub\n", This);
5106 showFixmes = FALSE;
5108 return This->softwareVertexProcessing;
5112 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5114 IWineD3DSwapChain *swapChain;
5115 HRESULT hr;
5117 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5119 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5120 if(hr == WINED3D_OK){
5121 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5122 IWineD3DSwapChain_Release(swapChain);
5123 }else{
5124 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5126 return hr;
5130 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5132 static BOOL showfixmes = TRUE;
5133 if(nSegments != 0.0f) {
5134 if( showfixmes) {
5135 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5136 showfixmes = FALSE;
5139 return WINED3D_OK;
5142 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5144 static BOOL showfixmes = TRUE;
5145 if( showfixmes) {
5146 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5147 showfixmes = FALSE;
5149 return 0.0f;
5152 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5154 /** TODO: remove casts to IWineD3DSurfaceImpl
5155 * NOTE: move code to surface to accomplish this
5156 ****************************************/
5157 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5158 int srcWidth, srcHeight;
5159 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5160 WINED3DFORMAT destFormat, srcFormat;
5161 UINT destSize;
5162 int srcLeft, destLeft, destTop;
5163 WINED3DPOOL srcPool, destPool;
5164 int offset = 0;
5165 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5166 glDescriptor *glDescription = NULL;
5167 GLenum dummy;
5168 int bpp;
5169 CONVERT_TYPES convert = NO_CONVERSION;
5171 WINED3DSURFACE_DESC winedesc;
5173 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5174 memset(&winedesc, 0, sizeof(winedesc));
5175 winedesc.Width = &srcSurfaceWidth;
5176 winedesc.Height = &srcSurfaceHeight;
5177 winedesc.Pool = &srcPool;
5178 winedesc.Format = &srcFormat;
5180 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5182 winedesc.Width = &destSurfaceWidth;
5183 winedesc.Height = &destSurfaceHeight;
5184 winedesc.Pool = &destPool;
5185 winedesc.Format = &destFormat;
5186 winedesc.Size = &destSize;
5188 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5190 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5191 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5192 return WINED3DERR_INVALIDCALL;
5195 /* This call loads the opengl surface directly, instead of copying the surface to the
5196 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5197 * copy in sysmem and use regular surface loading.
5199 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5200 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5201 if(convert != NO_CONVERSION) {
5202 return IWineD3DSurface_BltFast(pDestinationSurface,
5203 pDestPoint ? pDestPoint->x : 0,
5204 pDestPoint ? pDestPoint->y : 0,
5205 pSourceSurface, (RECT *) pSourceRect, 0);
5208 if (destFormat == WINED3DFMT_UNKNOWN) {
5209 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5210 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5212 /* Get the update surface description */
5213 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5216 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5218 ENTER_GL();
5220 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5221 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5222 checkGLcall("glActiveTextureARB");
5225 /* Make sure the surface is loaded and up to date */
5226 IWineD3DSurface_PreLoad(pDestinationSurface);
5228 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5230 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5231 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5232 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5233 srcLeft = pSourceRect ? pSourceRect->left : 0;
5234 destLeft = pDestPoint ? pDestPoint->x : 0;
5235 destTop = pDestPoint ? pDestPoint->y : 0;
5238 /* This function doesn't support compressed textures
5239 the pitch is just bytesPerPixel * width */
5240 if(srcWidth != srcSurfaceWidth || srcLeft ){
5241 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5242 offset += srcLeft * pSrcSurface->bytesPerPixel;
5243 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5245 /* TODO DXT formats */
5247 if(pSourceRect != NULL && pSourceRect->top != 0){
5248 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5250 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5251 ,This
5252 ,glDescription->level
5253 ,destLeft
5254 ,destTop
5255 ,srcWidth
5256 ,srcHeight
5257 ,glDescription->glFormat
5258 ,glDescription->glType
5259 ,IWineD3DSurface_GetData(pSourceSurface)
5262 /* Sanity check */
5263 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5265 /* need to lock the surface to get the data */
5266 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5269 /* TODO: Cube and volume support */
5270 if(rowoffset != 0){
5271 /* not a whole row so we have to do it a line at a time */
5272 int j;
5274 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5275 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5277 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5279 glTexSubImage2D(glDescription->target
5280 ,glDescription->level
5281 ,destLeft
5283 ,srcWidth
5285 ,glDescription->glFormat
5286 ,glDescription->glType
5287 ,data /* could be quicker using */
5289 data += rowoffset;
5292 } else { /* Full width, so just write out the whole texture */
5294 if (WINED3DFMT_DXT1 == destFormat ||
5295 WINED3DFMT_DXT2 == destFormat ||
5296 WINED3DFMT_DXT3 == destFormat ||
5297 WINED3DFMT_DXT4 == destFormat ||
5298 WINED3DFMT_DXT5 == destFormat) {
5299 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5300 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5301 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5302 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5303 } if (destFormat != srcFormat) {
5304 FIXME("Updating mixed format compressed texture is not curretly support\n");
5305 } else {
5306 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5307 glDescription->level,
5308 glDescription->glFormatInternal,
5309 srcWidth,
5310 srcHeight,
5312 destSize,
5313 IWineD3DSurface_GetData(pSourceSurface));
5315 } else {
5316 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5320 } else {
5321 glTexSubImage2D(glDescription->target
5322 ,glDescription->level
5323 ,destLeft
5324 ,destTop
5325 ,srcWidth
5326 ,srcHeight
5327 ,glDescription->glFormat
5328 ,glDescription->glType
5329 ,IWineD3DSurface_GetData(pSourceSurface)
5333 checkGLcall("glTexSubImage2D");
5335 LEAVE_GL();
5337 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5338 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5341 return WINED3D_OK;
5344 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5346 struct WineD3DRectPatch *patch;
5347 unsigned int i;
5348 struct list *e;
5349 BOOL found;
5350 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5352 if(!(Handle || pRectPatchInfo)) {
5353 /* TODO: Write a test for the return value, thus the FIXME */
5354 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5355 return WINED3DERR_INVALIDCALL;
5358 if(Handle) {
5359 i = PATCHMAP_HASHFUNC(Handle);
5360 found = FALSE;
5361 LIST_FOR_EACH(e, &This->patches[i]) {
5362 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5363 if(patch->Handle == Handle) {
5364 found = TRUE;
5365 break;
5369 if(!found) {
5370 TRACE("Patch does not exist. Creating a new one\n");
5371 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5372 patch->Handle = Handle;
5373 list_add_head(&This->patches[i], &patch->entry);
5374 } else {
5375 TRACE("Found existing patch %p\n", patch);
5377 } else {
5378 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5379 * attributes we have to tesselate, read back, and draw. This needs a patch
5380 * management structure instance. Create one.
5382 * A possible improvement is to check if a vertex shader is used, and if not directly
5383 * draw the patch.
5385 FIXME("Drawing an uncached patch. This is slow\n");
5386 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5389 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5390 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5391 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5392 HRESULT hr;
5393 TRACE("Tesselation density or patch info changed, retesselating\n");
5395 if(pRectPatchInfo) {
5396 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5398 patch->numSegs[0] = pNumSegs[0];
5399 patch->numSegs[1] = pNumSegs[1];
5400 patch->numSegs[2] = pNumSegs[2];
5401 patch->numSegs[3] = pNumSegs[3];
5403 hr = tesselate_rectpatch(This, patch);
5404 if(FAILED(hr)) {
5405 WARN("Patch tesselation failed\n");
5407 /* Do not release the handle to store the params of the patch */
5408 if(!Handle) {
5409 HeapFree(GetProcessHeap(), 0, patch);
5411 return hr;
5415 This->currentPatch = patch;
5416 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5417 This->currentPatch = NULL;
5419 /* Destroy uncached patches */
5420 if(!Handle) {
5421 HeapFree(GetProcessHeap(), 0, patch->mem);
5422 HeapFree(GetProcessHeap(), 0, patch);
5424 return WINED3D_OK;
5427 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5428 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5431 FIXME("(%p) : Stub\n", This);
5432 return WINED3D_OK;
5435 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5437 int i;
5438 struct WineD3DRectPatch *patch;
5439 struct list *e;
5440 TRACE("(%p) Handle(%d)\n", This, Handle);
5442 i = PATCHMAP_HASHFUNC(Handle);
5443 LIST_FOR_EACH(e, &This->patches[i]) {
5444 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5445 if(patch->Handle == Handle) {
5446 TRACE("Deleting patch %p\n", patch);
5447 list_remove(&patch->entry);
5448 HeapFree(GetProcessHeap(), 0, patch->mem);
5449 HeapFree(GetProcessHeap(), 0, patch);
5450 return WINED3D_OK;
5454 /* TODO: Write a test for the return value */
5455 FIXME("Attempt to destroy nonexistant patch\n");
5456 return WINED3DERR_INVALIDCALL;
5459 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5460 HRESULT hr;
5461 IWineD3DSwapChain *swapchain;
5463 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5464 if (SUCCEEDED(hr)) {
5465 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5466 return swapchain;
5469 return NULL;
5472 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5475 if (!*fbo) {
5476 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5477 checkGLcall("glGenFramebuffersEXT()");
5479 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5480 checkGLcall("glBindFramebuffer()");
5483 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5484 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5485 IWineD3DBaseTextureImpl *texture_impl;
5486 GLenum texttarget, target;
5487 GLint old_binding;
5489 texttarget = surface_impl->glDescription.target;
5490 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5491 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5493 IWineD3DSurface_PreLoad(surface);
5495 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5496 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5497 glBindTexture(target, old_binding);
5499 /* Update base texture states array */
5500 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5501 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5502 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5503 if (texture_impl->baseTexture.bindCount) {
5504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5507 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5510 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5511 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5513 checkGLcall("attach_surface_fbo");
5516 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5517 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5518 IWineD3DSwapChain *swapchain;
5520 swapchain = get_swapchain(surface);
5521 if (swapchain) {
5522 GLenum buffer;
5524 TRACE("Surface %p is onscreen\n", surface);
5526 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5527 buffer = surface_get_gl_buffer(surface, swapchain);
5528 glDrawBuffer(buffer);
5529 checkGLcall("glDrawBuffer()");
5530 } else {
5531 TRACE("Surface %p is offscreen\n", surface);
5532 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5533 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5536 if (rect) {
5537 glEnable(GL_SCISSOR_TEST);
5538 if(!swapchain) {
5539 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5540 } else {
5541 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5542 rect->x2 - rect->x1, rect->y2 - rect->y1);
5544 checkGLcall("glScissor");
5545 } else {
5546 glDisable(GL_SCISSOR_TEST);
5548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5550 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5553 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5554 glClear(GL_COLOR_BUFFER_BIT);
5555 checkGLcall("glClear");
5557 if (This->render_offscreen) {
5558 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5559 } else {
5560 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5561 checkGLcall("glBindFramebuffer()");
5564 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5565 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5566 glDrawBuffer(GL_BACK);
5567 checkGLcall("glDrawBuffer()");
5571 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5573 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5574 WINEDDBLTFX BltFx;
5575 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5577 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5578 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5579 return WINED3DERR_INVALIDCALL;
5582 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5583 color_fill_fbo(iface, pSurface, pRect, color);
5584 return WINED3D_OK;
5585 } else {
5586 /* Just forward this to the DirectDraw blitting engine */
5587 memset(&BltFx, 0, sizeof(BltFx));
5588 BltFx.dwSize = sizeof(BltFx);
5589 BltFx.u5.dwFillColor = color;
5590 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5594 /* rendertarget and deptth stencil functions */
5595 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5598 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5599 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5600 return WINED3DERR_INVALIDCALL;
5603 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5604 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5605 /* Note inc ref on returned surface */
5606 if(*ppRenderTarget != NULL)
5607 IWineD3DSurface_AddRef(*ppRenderTarget);
5608 return WINED3D_OK;
5611 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5613 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5614 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5615 IWineD3DSwapChainImpl *Swapchain;
5616 HRESULT hr;
5618 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5620 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5621 if(hr != WINED3D_OK) {
5622 ERR("Can't get the swapchain\n");
5623 return hr;
5626 /* Make sure to release the swapchain */
5627 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5629 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5630 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5631 return WINED3DERR_INVALIDCALL;
5633 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5634 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5635 return WINED3DERR_INVALIDCALL;
5638 if(Swapchain->frontBuffer != Front) {
5639 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5641 if(Swapchain->frontBuffer)
5642 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5643 Swapchain->frontBuffer = Front;
5645 if(Swapchain->frontBuffer) {
5646 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5650 if(Back && !Swapchain->backBuffer) {
5651 /* We need memory for the back buffer array - only one back buffer this way */
5652 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5653 if(!Swapchain->backBuffer) {
5654 ERR("Out of memory\n");
5655 return E_OUTOFMEMORY;
5659 if(Swapchain->backBuffer[0] != Back) {
5660 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5662 /* What to do about the context here in the case of multithreading? Not sure.
5663 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5665 ENTER_GL();
5666 if(!Swapchain->backBuffer[0]) {
5667 /* GL was told to draw to the front buffer at creation,
5668 * undo that
5670 glDrawBuffer(GL_BACK);
5671 checkGLcall("glDrawBuffer(GL_BACK)");
5672 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5673 Swapchain->presentParms.BackBufferCount = 1;
5674 } else if (!Back) {
5675 /* That makes problems - disable for now */
5676 /* glDrawBuffer(GL_FRONT); */
5677 checkGLcall("glDrawBuffer(GL_FRONT)");
5678 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5679 Swapchain->presentParms.BackBufferCount = 0;
5681 LEAVE_GL();
5683 if(Swapchain->backBuffer[0])
5684 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5685 Swapchain->backBuffer[0] = Back;
5687 if(Swapchain->backBuffer[0]) {
5688 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5689 } else {
5690 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5695 return WINED3D_OK;
5698 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5700 *ppZStencilSurface = This->depthStencilBuffer;
5701 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5703 if(*ppZStencilSurface != NULL) {
5704 /* Note inc ref on returned surface */
5705 IWineD3DSurface_AddRef(*ppZStencilSurface);
5707 return WINED3D_OK;
5710 /* TODO: Handle stencil attachments */
5711 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5715 TRACE("Set depth stencil to %p\n", depth_stencil);
5717 if (depth_stencil_impl) {
5718 if (depth_stencil_impl->current_renderbuffer) {
5719 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5720 checkGLcall("glFramebufferRenderbufferEXT()");
5721 } else {
5722 IWineD3DBaseTextureImpl *texture_impl;
5723 GLenum texttarget, target;
5724 GLint old_binding = 0;
5726 texttarget = depth_stencil_impl->glDescription.target;
5727 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5728 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5730 IWineD3DSurface_PreLoad(depth_stencil);
5732 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5733 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5734 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5735 glBindTexture(target, old_binding);
5737 /* Update base texture states array */
5738 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5739 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5740 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5741 if (texture_impl->baseTexture.bindCount) {
5742 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5745 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5748 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5749 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5750 checkGLcall("glFramebufferTexture2DEXT()");
5752 } else {
5753 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5754 checkGLcall("glFramebufferTexture2DEXT()");
5758 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5760 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5762 TRACE("Set render target %u to %p\n", idx, render_target);
5764 if (rtimpl) {
5765 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5766 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5767 } else {
5768 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5769 checkGLcall("glFramebufferTexture2DEXT()");
5771 This->draw_buffers[idx] = GL_NONE;
5775 static void check_fbo_status(IWineD3DDevice *iface) {
5776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5777 GLenum status;
5779 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5780 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5781 TRACE("FBO complete\n");
5782 } else {
5783 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5785 /* Dump the FBO attachments */
5786 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5787 IWineD3DSurfaceImpl *attachment;
5788 int i;
5790 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5791 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5792 if (attachment) {
5793 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5794 attachment->pow2Width, attachment->pow2Height);
5797 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5798 if (attachment) {
5799 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5800 attachment->pow2Width, attachment->pow2Height);
5806 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5808 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5809 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5811 if (!ds_impl) return FALSE;
5813 if (ds_impl->current_renderbuffer) {
5814 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5815 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5818 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5819 rt_impl->pow2Height != ds_impl->pow2Height);
5822 void apply_fbo_state(IWineD3DDevice *iface) {
5823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5824 unsigned int i;
5826 if (This->render_offscreen) {
5827 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5829 /* Apply render targets */
5830 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5831 IWineD3DSurface *render_target = This->render_targets[i];
5832 if (This->fbo_color_attachments[i] != render_target) {
5833 set_render_target_fbo(iface, i, render_target);
5834 This->fbo_color_attachments[i] = render_target;
5838 /* Apply depth targets */
5839 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5840 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5841 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5843 if (This->stencilBufferTarget) {
5844 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5846 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5847 This->fbo_depth_attachment = This->stencilBufferTarget;
5850 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5851 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5852 checkGLcall("glDrawBuffers()");
5853 } else {
5854 glDrawBuffer(This->draw_buffers[0]);
5855 checkGLcall("glDrawBuffer()");
5857 } else {
5858 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5861 check_fbo_status(iface);
5864 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5865 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5866 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5867 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5868 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5869 GLenum gl_filter;
5871 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5872 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5873 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5874 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5876 switch (filter) {
5877 case WINED3DTEXF_LINEAR:
5878 gl_filter = GL_LINEAR;
5879 break;
5881 default:
5882 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5883 case WINED3DTEXF_NONE:
5884 case WINED3DTEXF_POINT:
5885 gl_filter = GL_NEAREST;
5886 break;
5889 /* Attach src surface to src fbo */
5890 src_swapchain = get_swapchain(src_surface);
5891 if (src_swapchain) {
5892 GLenum buffer;
5894 TRACE("Source surface %p is onscreen\n", src_surface);
5895 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5897 ENTER_GL();
5898 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5899 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5900 glReadBuffer(buffer);
5901 checkGLcall("glReadBuffer()");
5903 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5904 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5905 } else {
5906 TRACE("Source surface %p is offscreen\n", src_surface);
5907 ENTER_GL();
5908 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5909 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5910 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5911 checkGLcall("glReadBuffer()");
5913 LEAVE_GL();
5915 /* Attach dst surface to dst fbo */
5916 dst_swapchain = get_swapchain(dst_surface);
5917 if (dst_swapchain) {
5918 GLenum buffer;
5920 TRACE("Destination surface %p is onscreen\n", dst_surface);
5921 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5923 ENTER_GL();
5924 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5925 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5926 glDrawBuffer(buffer);
5927 checkGLcall("glDrawBuffer()");
5929 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5930 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5931 } else {
5932 TRACE("Destination surface %p is offscreen\n", dst_surface);
5934 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5935 if(!src_swapchain) {
5936 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5939 ENTER_GL();
5940 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5941 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5942 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5943 checkGLcall("glDrawBuffer()");
5945 glDisable(GL_SCISSOR_TEST);
5946 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5948 if (flip) {
5949 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5950 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5951 checkGLcall("glBlitFramebuffer()");
5952 } else {
5953 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5954 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5955 checkGLcall("glBlitFramebuffer()");
5958 if (This->render_offscreen) {
5959 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5960 } else {
5961 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5962 checkGLcall("glBindFramebuffer()");
5965 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5966 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5967 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5968 glDrawBuffer(GL_BACK);
5969 checkGLcall("glDrawBuffer()");
5971 LEAVE_GL();
5974 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5976 WINED3DVIEWPORT viewport;
5978 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5980 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5981 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5982 return WINED3DERR_INVALIDCALL;
5985 /* MSDN says that null disables the render target
5986 but a device must always be associated with a render target
5987 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5989 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5990 for more details
5992 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5993 FIXME("Trying to set render target 0 to NULL\n");
5994 return WINED3DERR_INVALIDCALL;
5996 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5997 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);
5998 return WINED3DERR_INVALIDCALL;
6001 /* If we are trying to set what we already have, don't bother */
6002 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6003 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6004 return WINED3D_OK;
6006 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6007 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6008 This->render_targets[RenderTargetIndex] = pRenderTarget;
6010 /* Render target 0 is special */
6011 if(RenderTargetIndex == 0) {
6012 /* Finally, reset the viewport as the MSDN states. */
6013 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6014 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6015 viewport.X = 0;
6016 viewport.Y = 0;
6017 viewport.MaxZ = 1.0f;
6018 viewport.MinZ = 0.0f;
6019 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6020 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6021 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6023 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6025 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6026 * ctx properly.
6027 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6028 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6030 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6032 return WINED3D_OK;
6035 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6036 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6037 HRESULT hr = WINED3D_OK;
6038 IWineD3DSurface *tmp;
6040 TRACE("(%p) Swapping z-buffer\n",This);
6042 if (pNewZStencil == This->stencilBufferTarget) {
6043 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6044 } else {
6045 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6046 * depending on the renter target implementation being used.
6047 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6048 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6049 * stencil buffer and incure an extra memory overhead
6050 ******************************************************/
6052 tmp = This->stencilBufferTarget;
6053 This->stencilBufferTarget = pNewZStencil;
6054 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6055 /* should we be calling the parent or the wined3d surface? */
6056 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6057 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6058 hr = WINED3D_OK;
6060 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6061 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6063 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6064 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6068 return hr;
6071 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6072 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6074 /* TODO: the use of Impl is deprecated. */
6075 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6076 WINED3DLOCKED_RECT lockedRect;
6078 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6080 /* some basic validation checks */
6081 if(This->cursorTexture) {
6082 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6083 ENTER_GL();
6084 glDeleteTextures(1, &This->cursorTexture);
6085 LEAVE_GL();
6086 This->cursorTexture = 0;
6089 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6090 This->haveHardwareCursor = TRUE;
6091 else
6092 This->haveHardwareCursor = FALSE;
6094 if(pCursorBitmap) {
6095 WINED3DLOCKED_RECT rect;
6097 /* MSDN: Cursor must be A8R8G8B8 */
6098 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6099 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6100 return WINED3DERR_INVALIDCALL;
6103 /* MSDN: Cursor must be smaller than the display mode */
6104 if(pSur->currentDesc.Width > This->ddraw_width ||
6105 pSur->currentDesc.Height > This->ddraw_height) {
6106 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);
6107 return WINED3DERR_INVALIDCALL;
6110 if (!This->haveHardwareCursor) {
6111 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6113 /* Do not store the surface's pointer because the application may
6114 * release it after setting the cursor image. Windows doesn't
6115 * addref the set surface, so we can't do this either without
6116 * creating circular refcount dependencies. Copy out the gl texture
6117 * instead.
6119 This->cursorWidth = pSur->currentDesc.Width;
6120 This->cursorHeight = pSur->currentDesc.Height;
6121 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6123 const GlPixelFormatDesc *glDesc;
6124 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6125 char *mem, *bits = (char *)rect.pBits;
6126 GLint intfmt = glDesc->glInternal;
6127 GLint format = glDesc->glFormat;
6128 GLint type = glDesc->glType;
6129 INT height = This->cursorHeight;
6130 INT width = This->cursorWidth;
6131 INT bpp = tableEntry->bpp;
6132 INT i;
6134 /* Reformat the texture memory (pitch and width can be
6135 * different) */
6136 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6137 for(i = 0; i < height; i++)
6138 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6139 IWineD3DSurface_UnlockRect(pCursorBitmap);
6140 ENTER_GL();
6142 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6143 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6144 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6147 /* Make sure that a proper texture unit is selected */
6148 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6149 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6150 checkGLcall("glActiveTextureARB");
6152 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6153 /* Create a new cursor texture */
6154 glGenTextures(1, &This->cursorTexture);
6155 checkGLcall("glGenTextures");
6156 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6157 checkGLcall("glBindTexture");
6158 /* Copy the bitmap memory into the cursor texture */
6159 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6160 HeapFree(GetProcessHeap(), 0, mem);
6161 checkGLcall("glTexImage2D");
6163 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6164 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6165 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6168 LEAVE_GL();
6170 else
6172 FIXME("A cursor texture was not returned.\n");
6173 This->cursorTexture = 0;
6176 else
6178 /* Draw a hardware cursor */
6179 ICONINFO cursorInfo;
6180 HCURSOR cursor;
6181 /* Create and clear maskBits because it is not needed for
6182 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6183 * chunks. */
6184 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6185 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6186 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6187 WINED3DLOCK_NO_DIRTY_UPDATE |
6188 WINED3DLOCK_READONLY
6190 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6191 pSur->currentDesc.Height);
6193 cursorInfo.fIcon = FALSE;
6194 cursorInfo.xHotspot = XHotSpot;
6195 cursorInfo.yHotspot = YHotSpot;
6196 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6197 pSur->currentDesc.Height, 1,
6198 1, &maskBits);
6199 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6200 pSur->currentDesc.Height, 1,
6201 32, lockedRect.pBits);
6202 IWineD3DSurface_UnlockRect(pCursorBitmap);
6203 /* Create our cursor and clean up. */
6204 cursor = CreateIconIndirect(&cursorInfo);
6205 SetCursor(cursor);
6206 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6207 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6208 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6209 This->hardwareCursor = cursor;
6210 HeapFree(GetProcessHeap(), 0, maskBits);
6214 This->xHotSpot = XHotSpot;
6215 This->yHotSpot = YHotSpot;
6216 return WINED3D_OK;
6219 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6221 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6223 This->xScreenSpace = XScreenSpace;
6224 This->yScreenSpace = YScreenSpace;
6226 return;
6230 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6232 BOOL oldVisible = This->bCursorVisible;
6233 POINT pt;
6235 TRACE("(%p) : visible(%d)\n", This, bShow);
6238 * When ShowCursor is first called it should make the cursor appear at the OS's last
6239 * known cursor position. Because of this, some applications just repetitively call
6240 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6242 GetCursorPos(&pt);
6243 This->xScreenSpace = pt.x;
6244 This->yScreenSpace = pt.y;
6246 if (This->haveHardwareCursor) {
6247 This->bCursorVisible = bShow;
6248 if (bShow)
6249 SetCursor(This->hardwareCursor);
6250 else
6251 SetCursor(NULL);
6253 else
6255 if (This->cursorTexture)
6256 This->bCursorVisible = bShow;
6259 return oldVisible;
6262 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6263 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6264 TRACE("(%p) : state (%u)\n", This, This->state);
6265 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6266 switch (This->state) {
6267 case WINED3D_OK:
6268 return WINED3D_OK;
6269 case WINED3DERR_DEVICELOST:
6271 ResourceList *resourceList = This->resources;
6272 while (NULL != resourceList) {
6273 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6274 return WINED3DERR_DEVICENOTRESET;
6275 resourceList = resourceList->next;
6277 return WINED3DERR_DEVICELOST;
6279 case WINED3DERR_DRIVERINTERNALERROR:
6280 return WINED3DERR_DRIVERINTERNALERROR;
6283 /* Unknown state */
6284 return WINED3DERR_DRIVERINTERNALERROR;
6288 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6290 /** FIXME: Resource tracking needs to be done,
6291 * The closes we can do to this is set the priorities of all managed textures low
6292 * and then reset them.
6293 ***********************************************************/
6294 FIXME("(%p) : stub\n", This);
6295 return WINED3D_OK;
6298 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6299 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6301 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6302 if(surface->Flags & SFLAG_DIBSECTION) {
6303 /* Release the DC */
6304 SelectObject(surface->hDC, surface->dib.holdbitmap);
6305 DeleteDC(surface->hDC);
6306 /* Release the DIB section */
6307 DeleteObject(surface->dib.DIBsection);
6308 surface->dib.bitmap_data = NULL;
6309 surface->resource.allocatedMemory = NULL;
6310 surface->Flags &= ~SFLAG_DIBSECTION;
6312 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6313 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6314 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6315 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6316 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6317 } else {
6318 surface->pow2Width = surface->pow2Height = 1;
6319 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6320 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6322 if(surface->glDescription.textureName) {
6323 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6324 ENTER_GL();
6325 glDeleteTextures(1, &surface->glDescription.textureName);
6326 LEAVE_GL();
6327 surface->glDescription.textureName = 0;
6328 surface->Flags &= ~SFLAG_CLIENT;
6330 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6331 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6332 surface->Flags |= SFLAG_NONPOW2;
6333 } else {
6334 surface->Flags &= ~SFLAG_NONPOW2;
6336 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6337 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6340 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6342 IWineD3DSwapChainImpl *swapchain;
6343 HRESULT hr;
6344 BOOL DisplayModeChanged = FALSE;
6345 WINED3DDISPLAYMODE mode;
6346 TRACE("(%p)\n", This);
6348 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6349 if(FAILED(hr)) {
6350 ERR("Failed to get the first implicit swapchain\n");
6351 return hr;
6354 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6355 * on an existing gl context, so there's no real need for recreation.
6357 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6359 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6361 TRACE("New params:\n");
6362 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6363 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6364 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6365 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6366 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6367 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6368 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6369 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6370 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6371 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6372 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6373 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6374 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6376 /* No special treatment of these parameters. Just store them */
6377 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6378 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6379 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6380 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6382 /* What to do about these? */
6383 if(pPresentationParameters->BackBufferCount != 0 &&
6384 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6385 ERR("Cannot change the back buffer count yet\n");
6387 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6388 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6389 ERR("Cannot change the back buffer format yet\n");
6391 if(pPresentationParameters->hDeviceWindow != NULL &&
6392 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6393 ERR("Cannot change the device window yet\n");
6395 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6396 ERR("What do do about a changed auto depth stencil parameter?\n");
6399 if(pPresentationParameters->Windowed) {
6400 mode.Width = swapchain->orig_width;
6401 mode.Height = swapchain->orig_height;
6402 mode.RefreshRate = 0;
6403 mode.Format = swapchain->presentParms.BackBufferFormat;
6404 } else {
6405 mode.Width = pPresentationParameters->BackBufferWidth;
6406 mode.Height = pPresentationParameters->BackBufferHeight;
6407 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6408 mode.Format = swapchain->presentParms.BackBufferFormat;
6410 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6411 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6412 pPresentationParameters->BackBufferWidth,
6413 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6416 /* Should Width == 800 && Height == 0 set 800x600? */
6417 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6418 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6419 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6421 WINED3DVIEWPORT vp;
6422 int i;
6424 vp.X = 0;
6425 vp.Y = 0;
6426 vp.Width = pPresentationParameters->BackBufferWidth;
6427 vp.Height = pPresentationParameters->BackBufferHeight;
6428 vp.MinZ = 0;
6429 vp.MaxZ = 1;
6431 if(!pPresentationParameters->Windowed) {
6432 DisplayModeChanged = TRUE;
6434 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6435 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6437 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6438 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6439 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6442 /* Now set the new viewport */
6443 IWineD3DDevice_SetViewport(iface, &vp);
6446 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6447 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6448 DisplayModeChanged) {
6450 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6451 if(!pPresentationParameters->Windowed) {
6452 IWineD3DDevice_SetFullscreen(iface, TRUE);
6455 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6457 /* Switching out of fullscreen mode? First set the original res, then change the window */
6458 if(pPresentationParameters->Windowed) {
6459 IWineD3DDevice_SetFullscreen(iface, FALSE);
6461 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6464 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6465 return WINED3D_OK;
6468 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6470 /** FIXME: always true at the moment **/
6471 if(!bEnableDialogs) {
6472 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6474 return WINED3D_OK;
6478 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6480 TRACE("(%p) : pParameters %p\n", This, pParameters);
6482 *pParameters = This->createParms;
6483 return WINED3D_OK;
6486 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6487 IWineD3DSwapChain *swapchain;
6488 HRESULT hrc = WINED3D_OK;
6490 TRACE("Relaying to swapchain\n");
6492 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6493 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6494 IWineD3DSwapChain_Release(swapchain);
6496 return;
6499 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6500 IWineD3DSwapChain *swapchain;
6501 HRESULT hrc = WINED3D_OK;
6503 TRACE("Relaying to swapchain\n");
6505 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6506 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6507 IWineD3DSwapChain_Release(swapchain);
6509 return;
6513 /** ********************************************************
6514 * Notification functions
6515 ** ********************************************************/
6516 /** This function must be called in the release of a resource when ref == 0,
6517 * the contents of resource must still be correct,
6518 * any handels to other resource held by the caller must be closed
6519 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6520 *****************************************************/
6521 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6523 ResourceList* resourceList;
6525 TRACE("(%p) : resource %p\n", This, resource);
6526 /* add a new texture to the frot of the linked list */
6527 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6528 resourceList->resource = resource;
6530 /* Get the old head */
6531 resourceList->next = This->resources;
6533 This->resources = resourceList;
6534 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6536 return;
6539 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6541 ResourceList* resourceList = NULL;
6542 ResourceList* previousResourceList = NULL;
6544 TRACE("(%p) : resource %p\n", This, resource);
6546 resourceList = This->resources;
6548 while (resourceList != NULL) {
6549 if(resourceList->resource == resource) break;
6550 previousResourceList = resourceList;
6551 resourceList = resourceList->next;
6554 if (resourceList == NULL) {
6555 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6556 return;
6557 } else {
6558 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6560 /* make sure we don't leave a hole in the list */
6561 if (previousResourceList != NULL) {
6562 previousResourceList->next = resourceList->next;
6563 } else {
6564 This->resources = resourceList->next;
6567 return;
6571 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6573 int counter;
6575 TRACE("(%p) : resource %p\n", This, resource);
6576 switch(IWineD3DResource_GetType(resource)){
6577 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6578 case WINED3DRTYPE_SURFACE: {
6579 unsigned int i;
6581 /* Cleanup any FBO attachments if d3d is enabled */
6582 if(This->d3d_initialized) {
6583 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6584 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6585 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6586 set_render_target_fbo(iface, i, NULL);
6587 This->fbo_color_attachments[i] = NULL;
6590 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6591 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6592 set_depth_stencil_fbo(iface, NULL);
6593 This->fbo_depth_attachment = NULL;
6597 break;
6599 case WINED3DRTYPE_TEXTURE:
6600 case WINED3DRTYPE_CUBETEXTURE:
6601 case WINED3DRTYPE_VOLUMETEXTURE:
6602 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6603 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6604 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6605 This->stateBlock->textures[counter] = NULL;
6607 if (This->updateStateBlock != This->stateBlock ){
6608 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6609 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6610 This->updateStateBlock->textures[counter] = NULL;
6614 break;
6615 case WINED3DRTYPE_VOLUME:
6616 /* TODO: nothing really? */
6617 break;
6618 case WINED3DRTYPE_VERTEXBUFFER:
6619 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6621 int streamNumber;
6622 TRACE("Cleaning up stream pointers\n");
6624 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6625 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6626 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6628 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6629 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6630 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6631 This->updateStateBlock->streamSource[streamNumber] = 0;
6632 /* Set changed flag? */
6635 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) */
6636 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6637 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6638 This->stateBlock->streamSource[streamNumber] = 0;
6641 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6642 else { /* This shouldn't happen */
6643 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6645 #endif
6649 break;
6650 case WINED3DRTYPE_INDEXBUFFER:
6651 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6652 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6653 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6654 This->updateStateBlock->pIndexData = NULL;
6657 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6658 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6659 This->stateBlock->pIndexData = NULL;
6663 break;
6664 default:
6665 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6666 break;
6670 /* Remove the resoruce from the resourceStore */
6671 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6673 TRACE("Resource released\n");
6677 /**********************************************************
6678 * IWineD3DDevice VTbl follows
6679 **********************************************************/
6681 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6683 /*** IUnknown methods ***/
6684 IWineD3DDeviceImpl_QueryInterface,
6685 IWineD3DDeviceImpl_AddRef,
6686 IWineD3DDeviceImpl_Release,
6687 /*** IWineD3DDevice methods ***/
6688 IWineD3DDeviceImpl_GetParent,
6689 /*** Creation methods**/
6690 IWineD3DDeviceImpl_CreateVertexBuffer,
6691 IWineD3DDeviceImpl_CreateIndexBuffer,
6692 IWineD3DDeviceImpl_CreateStateBlock,
6693 IWineD3DDeviceImpl_CreateSurface,
6694 IWineD3DDeviceImpl_CreateTexture,
6695 IWineD3DDeviceImpl_CreateVolumeTexture,
6696 IWineD3DDeviceImpl_CreateVolume,
6697 IWineD3DDeviceImpl_CreateCubeTexture,
6698 IWineD3DDeviceImpl_CreateQuery,
6699 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6700 IWineD3DDeviceImpl_CreateVertexDeclaration,
6701 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6702 IWineD3DDeviceImpl_CreateVertexShader,
6703 IWineD3DDeviceImpl_CreatePixelShader,
6704 IWineD3DDeviceImpl_CreatePalette,
6705 /*** Odd functions **/
6706 IWineD3DDeviceImpl_Init3D,
6707 IWineD3DDeviceImpl_Uninit3D,
6708 IWineD3DDeviceImpl_SetFullscreen,
6709 IWineD3DDeviceImpl_SetMultithreaded,
6710 IWineD3DDeviceImpl_EvictManagedResources,
6711 IWineD3DDeviceImpl_GetAvailableTextureMem,
6712 IWineD3DDeviceImpl_GetBackBuffer,
6713 IWineD3DDeviceImpl_GetCreationParameters,
6714 IWineD3DDeviceImpl_GetDeviceCaps,
6715 IWineD3DDeviceImpl_GetDirect3D,
6716 IWineD3DDeviceImpl_GetDisplayMode,
6717 IWineD3DDeviceImpl_SetDisplayMode,
6718 IWineD3DDeviceImpl_GetHWND,
6719 IWineD3DDeviceImpl_SetHWND,
6720 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6721 IWineD3DDeviceImpl_GetRasterStatus,
6722 IWineD3DDeviceImpl_GetSwapChain,
6723 IWineD3DDeviceImpl_Reset,
6724 IWineD3DDeviceImpl_SetDialogBoxMode,
6725 IWineD3DDeviceImpl_SetCursorProperties,
6726 IWineD3DDeviceImpl_SetCursorPosition,
6727 IWineD3DDeviceImpl_ShowCursor,
6728 IWineD3DDeviceImpl_TestCooperativeLevel,
6729 /*** Getters and setters **/
6730 IWineD3DDeviceImpl_SetClipPlane,
6731 IWineD3DDeviceImpl_GetClipPlane,
6732 IWineD3DDeviceImpl_SetClipStatus,
6733 IWineD3DDeviceImpl_GetClipStatus,
6734 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6735 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6736 IWineD3DDeviceImpl_SetDepthStencilSurface,
6737 IWineD3DDeviceImpl_GetDepthStencilSurface,
6738 IWineD3DDeviceImpl_SetFVF,
6739 IWineD3DDeviceImpl_GetFVF,
6740 IWineD3DDeviceImpl_SetGammaRamp,
6741 IWineD3DDeviceImpl_GetGammaRamp,
6742 IWineD3DDeviceImpl_SetIndices,
6743 IWineD3DDeviceImpl_GetIndices,
6744 IWineD3DDeviceImpl_SetBaseVertexIndex,
6745 IWineD3DDeviceImpl_GetBaseVertexIndex,
6746 IWineD3DDeviceImpl_SetLight,
6747 IWineD3DDeviceImpl_GetLight,
6748 IWineD3DDeviceImpl_SetLightEnable,
6749 IWineD3DDeviceImpl_GetLightEnable,
6750 IWineD3DDeviceImpl_SetMaterial,
6751 IWineD3DDeviceImpl_GetMaterial,
6752 IWineD3DDeviceImpl_SetNPatchMode,
6753 IWineD3DDeviceImpl_GetNPatchMode,
6754 IWineD3DDeviceImpl_SetPaletteEntries,
6755 IWineD3DDeviceImpl_GetPaletteEntries,
6756 IWineD3DDeviceImpl_SetPixelShader,
6757 IWineD3DDeviceImpl_GetPixelShader,
6758 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6759 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6760 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6761 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6762 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6763 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6764 IWineD3DDeviceImpl_SetRenderState,
6765 IWineD3DDeviceImpl_GetRenderState,
6766 IWineD3DDeviceImpl_SetRenderTarget,
6767 IWineD3DDeviceImpl_GetRenderTarget,
6768 IWineD3DDeviceImpl_SetFrontBackBuffers,
6769 IWineD3DDeviceImpl_SetSamplerState,
6770 IWineD3DDeviceImpl_GetSamplerState,
6771 IWineD3DDeviceImpl_SetScissorRect,
6772 IWineD3DDeviceImpl_GetScissorRect,
6773 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6774 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6775 IWineD3DDeviceImpl_SetStreamSource,
6776 IWineD3DDeviceImpl_GetStreamSource,
6777 IWineD3DDeviceImpl_SetStreamSourceFreq,
6778 IWineD3DDeviceImpl_GetStreamSourceFreq,
6779 IWineD3DDeviceImpl_SetTexture,
6780 IWineD3DDeviceImpl_GetTexture,
6781 IWineD3DDeviceImpl_SetTextureStageState,
6782 IWineD3DDeviceImpl_GetTextureStageState,
6783 IWineD3DDeviceImpl_SetTransform,
6784 IWineD3DDeviceImpl_GetTransform,
6785 IWineD3DDeviceImpl_SetVertexDeclaration,
6786 IWineD3DDeviceImpl_GetVertexDeclaration,
6787 IWineD3DDeviceImpl_SetVertexShader,
6788 IWineD3DDeviceImpl_GetVertexShader,
6789 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6790 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6791 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6792 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6793 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6794 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6795 IWineD3DDeviceImpl_SetViewport,
6796 IWineD3DDeviceImpl_GetViewport,
6797 IWineD3DDeviceImpl_MultiplyTransform,
6798 IWineD3DDeviceImpl_ValidateDevice,
6799 IWineD3DDeviceImpl_ProcessVertices,
6800 /*** State block ***/
6801 IWineD3DDeviceImpl_BeginStateBlock,
6802 IWineD3DDeviceImpl_EndStateBlock,
6803 /*** Scene management ***/
6804 IWineD3DDeviceImpl_BeginScene,
6805 IWineD3DDeviceImpl_EndScene,
6806 IWineD3DDeviceImpl_Present,
6807 IWineD3DDeviceImpl_Clear,
6808 /*** Drawing ***/
6809 IWineD3DDeviceImpl_DrawPrimitive,
6810 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6811 IWineD3DDeviceImpl_DrawPrimitiveUP,
6812 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6813 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6814 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6815 IWineD3DDeviceImpl_DrawRectPatch,
6816 IWineD3DDeviceImpl_DrawTriPatch,
6817 IWineD3DDeviceImpl_DeletePatch,
6818 IWineD3DDeviceImpl_ColorFill,
6819 IWineD3DDeviceImpl_UpdateTexture,
6820 IWineD3DDeviceImpl_UpdateSurface,
6821 IWineD3DDeviceImpl_GetFrontBufferData,
6822 /*** object tracking ***/
6823 IWineD3DDeviceImpl_ResourceReleased
6827 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6828 WINED3DRS_ALPHABLENDENABLE ,
6829 WINED3DRS_ALPHAFUNC ,
6830 WINED3DRS_ALPHAREF ,
6831 WINED3DRS_ALPHATESTENABLE ,
6832 WINED3DRS_BLENDOP ,
6833 WINED3DRS_COLORWRITEENABLE ,
6834 WINED3DRS_DESTBLEND ,
6835 WINED3DRS_DITHERENABLE ,
6836 WINED3DRS_FILLMODE ,
6837 WINED3DRS_FOGDENSITY ,
6838 WINED3DRS_FOGEND ,
6839 WINED3DRS_FOGSTART ,
6840 WINED3DRS_LASTPIXEL ,
6841 WINED3DRS_SHADEMODE ,
6842 WINED3DRS_SRCBLEND ,
6843 WINED3DRS_STENCILENABLE ,
6844 WINED3DRS_STENCILFAIL ,
6845 WINED3DRS_STENCILFUNC ,
6846 WINED3DRS_STENCILMASK ,
6847 WINED3DRS_STENCILPASS ,
6848 WINED3DRS_STENCILREF ,
6849 WINED3DRS_STENCILWRITEMASK ,
6850 WINED3DRS_STENCILZFAIL ,
6851 WINED3DRS_TEXTUREFACTOR ,
6852 WINED3DRS_WRAP0 ,
6853 WINED3DRS_WRAP1 ,
6854 WINED3DRS_WRAP2 ,
6855 WINED3DRS_WRAP3 ,
6856 WINED3DRS_WRAP4 ,
6857 WINED3DRS_WRAP5 ,
6858 WINED3DRS_WRAP6 ,
6859 WINED3DRS_WRAP7 ,
6860 WINED3DRS_ZENABLE ,
6861 WINED3DRS_ZFUNC ,
6862 WINED3DRS_ZWRITEENABLE
6865 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6866 WINED3DTSS_ADDRESSW ,
6867 WINED3DTSS_ALPHAARG0 ,
6868 WINED3DTSS_ALPHAARG1 ,
6869 WINED3DTSS_ALPHAARG2 ,
6870 WINED3DTSS_ALPHAOP ,
6871 WINED3DTSS_BUMPENVLOFFSET ,
6872 WINED3DTSS_BUMPENVLSCALE ,
6873 WINED3DTSS_BUMPENVMAT00 ,
6874 WINED3DTSS_BUMPENVMAT01 ,
6875 WINED3DTSS_BUMPENVMAT10 ,
6876 WINED3DTSS_BUMPENVMAT11 ,
6877 WINED3DTSS_COLORARG0 ,
6878 WINED3DTSS_COLORARG1 ,
6879 WINED3DTSS_COLORARG2 ,
6880 WINED3DTSS_COLOROP ,
6881 WINED3DTSS_RESULTARG ,
6882 WINED3DTSS_TEXCOORDINDEX ,
6883 WINED3DTSS_TEXTURETRANSFORMFLAGS
6886 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6887 WINED3DSAMP_ADDRESSU ,
6888 WINED3DSAMP_ADDRESSV ,
6889 WINED3DSAMP_ADDRESSW ,
6890 WINED3DSAMP_BORDERCOLOR ,
6891 WINED3DSAMP_MAGFILTER ,
6892 WINED3DSAMP_MINFILTER ,
6893 WINED3DSAMP_MIPFILTER ,
6894 WINED3DSAMP_MIPMAPLODBIAS ,
6895 WINED3DSAMP_MAXMIPLEVEL ,
6896 WINED3DSAMP_MAXANISOTROPY ,
6897 WINED3DSAMP_SRGBTEXTURE ,
6898 WINED3DSAMP_ELEMENTINDEX
6901 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6902 WINED3DRS_AMBIENT ,
6903 WINED3DRS_AMBIENTMATERIALSOURCE ,
6904 WINED3DRS_CLIPPING ,
6905 WINED3DRS_CLIPPLANEENABLE ,
6906 WINED3DRS_COLORVERTEX ,
6907 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6908 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6909 WINED3DRS_FOGDENSITY ,
6910 WINED3DRS_FOGEND ,
6911 WINED3DRS_FOGSTART ,
6912 WINED3DRS_FOGTABLEMODE ,
6913 WINED3DRS_FOGVERTEXMODE ,
6914 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6915 WINED3DRS_LIGHTING ,
6916 WINED3DRS_LOCALVIEWER ,
6917 WINED3DRS_MULTISAMPLEANTIALIAS ,
6918 WINED3DRS_MULTISAMPLEMASK ,
6919 WINED3DRS_NORMALIZENORMALS ,
6920 WINED3DRS_PATCHEDGESTYLE ,
6921 WINED3DRS_POINTSCALE_A ,
6922 WINED3DRS_POINTSCALE_B ,
6923 WINED3DRS_POINTSCALE_C ,
6924 WINED3DRS_POINTSCALEENABLE ,
6925 WINED3DRS_POINTSIZE ,
6926 WINED3DRS_POINTSIZE_MAX ,
6927 WINED3DRS_POINTSIZE_MIN ,
6928 WINED3DRS_POINTSPRITEENABLE ,
6929 WINED3DRS_RANGEFOGENABLE ,
6930 WINED3DRS_SPECULARMATERIALSOURCE ,
6931 WINED3DRS_TWEENFACTOR ,
6932 WINED3DRS_VERTEXBLEND
6935 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6936 WINED3DTSS_TEXCOORDINDEX ,
6937 WINED3DTSS_TEXTURETRANSFORMFLAGS
6940 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6941 WINED3DSAMP_DMAPOFFSET
6944 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6945 DWORD rep = StateTable[state].representative;
6946 DWORD idx;
6947 BYTE shift;
6948 UINT i;
6949 WineD3DContext *context;
6951 if(!rep) return;
6952 for(i = 0; i < This->numContexts; i++) {
6953 context = This->contexts[i];
6954 if(isStateDirty(context, rep)) continue;
6956 context->dirtyArray[context->numDirtyEntries++] = rep;
6957 idx = rep >> 5;
6958 shift = rep & 0x1f;
6959 context->isStateDirty[idx] |= (1 << shift);