wined3d: Attach the correct surface the the fbo.
[wine/multimedia.git] / dlls / wined3d / device.c
blob92b094310241ee0ea196f8f200508ae5ee781f7a
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2007 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 globalChangeGlRam(_size); \
104 object->resource.allocatedMemory = (0 == _size ? NULL : Pool == WINED3DPOOL_DEFAULT ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size)); \
105 if (object->resource.allocatedMemory == NULL && _size != 0 && Pool != WINED3DPOOL_DEFAULT) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 *pp##type = (IWineD3D##type *) object; \
112 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
113 TRACE("(%p) : Created resource %p\n", This, object); \
116 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
117 _basetexture.levels = Levels; \
118 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
119 _basetexture.LOD = 0; \
120 _basetexture.dirty = TRUE; \
121 _basetexture.is_srgb = FALSE; \
122 _basetexture.srgb_mode_change_count = 0; \
125 /**********************************************************
126 * Global variable / Constants follow
127 **********************************************************/
128 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
130 /**********************************************************
131 * IUnknown parts follows
132 **********************************************************/
134 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
138 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
139 if (IsEqualGUID(riid, &IID_IUnknown)
140 || IsEqualGUID(riid, &IID_IWineD3DBase)
141 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
142 IUnknown_AddRef(iface);
143 *ppobj = This;
144 return S_OK;
146 *ppobj = NULL;
147 return E_NOINTERFACE;
150 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
152 ULONG refCount = InterlockedIncrement(&This->ref);
154 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
155 return refCount;
158 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
160 ULONG refCount = InterlockedDecrement(&This->ref);
162 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
164 if (!refCount) {
165 if (This->fbo) {
166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
168 if (This->src_fbo) {
169 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
171 if (This->dst_fbo) {
172 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
175 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
177 /* TODO: Clean up all the surfaces and textures! */
178 /* NOTE: You must release the parent if the object was created via a callback
179 ** ***************************/
181 if (This->resources != NULL ) {
182 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
183 dumpResources(This->resources);
186 if(This->contexts) ERR("Context array not freed!\n");
187 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
188 This->haveHardwareCursor = FALSE;
190 IWineD3D_Release(This->wineD3D);
191 This->wineD3D = NULL;
192 HeapFree(GetProcessHeap(), 0, This);
193 TRACE("Freed device %p\n", This);
194 This = NULL;
196 return refCount;
199 /**********************************************************
200 * IWineD3DDevice implementation follows
201 **********************************************************/
202 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
203 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
204 *pParent = This->parent;
205 IUnknown_AddRef(This->parent);
206 return WINED3D_OK;
209 static void CreateVBO(IWineD3DVertexBufferImpl *object) {
210 IWineD3DDeviceImpl *This = object->resource.wineD3DDevice; /* Needed for GL_EXTCALL */
211 GLenum error, glUsage;
212 DWORD vboUsage = object->resource.usage;
213 if(object->Flags & VBFLAG_VBOCREATEFAIL) {
214 WARN("Creating a vbo failed once, not trying again\n");
215 return;
218 TRACE("Creating an OpenGL vertex buffer object for IWineD3DVertexBuffer %p Usage(%s)\n", object, debug_d3dusage(vboUsage));
220 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
221 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
222 ENTER_GL();
224 /* Make sure that the gl error is cleared. Do not use checkGLcall
225 * here because checkGLcall just prints a fixme and continues. However,
226 * if an error during VBO creation occurs we can fall back to non-vbo operation
227 * with full functionality(but performance loss)
229 while(glGetError() != GL_NO_ERROR);
231 /* Basically the FVF parameter passed to CreateVertexBuffer is no good
232 * It is the FVF set with IWineD3DDevice::SetFVF or the Vertex Declaration set with
233 * IWineD3DDevice::SetVertexDeclaration that decides how the vertices in the buffer
234 * look like. This means that on each DrawPrimitive call the vertex buffer has to be verified
235 * to check if the rhw and color values are in the correct format.
238 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
239 error = glGetError();
240 if(object->vbo == 0 || error != GL_NO_ERROR) {
241 WARN("Failed to create a VBO with error %s (%#x)\n", debug_glerror(error), error);
242 goto error;
245 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, object->vbo));
246 error = glGetError();
247 if(error != GL_NO_ERROR) {
248 WARN("Failed to bind the VBO with error %s (%#x)\n", debug_glerror(error), error);
249 goto error;
252 /* Don't use static, because dx apps tend to update the buffer
253 * quite often even if they specify 0 usage. Because we always keep the local copy
254 * we never read from the vbo and can create a write only opengl buffer.
256 switch(vboUsage & (WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC) ) {
257 case WINED3DUSAGE_WRITEONLY | WINED3DUSAGE_DYNAMIC:
258 case WINED3DUSAGE_DYNAMIC:
259 TRACE("Gl usage = GL_STREAM_DRAW\n");
260 glUsage = GL_STREAM_DRAW_ARB;
261 break;
262 case WINED3DUSAGE_WRITEONLY:
263 default:
264 TRACE("Gl usage = GL_DYNAMIC_DRAW\n");
265 glUsage = GL_DYNAMIC_DRAW_ARB;
266 break;
269 /* Reserve memory for the buffer. The amount of data won't change
270 * so we are safe with calling glBufferData once with a NULL ptr and
271 * calling glBufferSubData on updates
273 GL_EXTCALL(glBufferDataARB(GL_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
274 error = glGetError();
275 if(error != GL_NO_ERROR) {
276 WARN("glBufferDataARB failed with error %s (%#x)\n", debug_glerror(error), error);
277 goto error;
280 LEAVE_GL();
282 return;
283 error:
284 /* Clean up all vbo init, but continue because we can work without a vbo :-) */
285 FIXME("Failed to create a vertex buffer object. Continuing, but performance issues can occur\n");
286 if(object->vbo) GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
287 object->vbo = 0;
288 object->Flags |= VBFLAG_VBOCREATEFAIL;
289 LEAVE_GL();
290 return;
293 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
294 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
295 IUnknown *parent) {
296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
297 IWineD3DVertexBufferImpl *object;
298 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
299 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
300 BOOL conv;
302 if(Size == 0) {
303 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
304 *ppVertexBuffer = NULL;
305 return WINED3DERR_INVALIDCALL;
308 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
310 TRACE("(%p) : Size=%d, Usage=%d, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
311 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
313 if (Pool == WINED3DPOOL_DEFAULT ) { /* Allocate some system memory for now */
314 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, object->resource.size);
316 object->fvf = FVF;
318 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
319 * drawStridedFast (half-life 2).
321 * Basically converting the vertices in the buffer is quite expensive, and observations
322 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
323 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
325 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
326 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
327 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
328 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
329 * dx7 apps.
330 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
331 * more. In this call we can convert dx7 buffers too.
333 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
334 if( GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT) && Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) &&
335 (dxVersion > 7 || !conv) ) {
336 CreateVBO(object);
338 return WINED3D_OK;
341 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
342 GLenum error, glUsage;
343 TRACE("Creating VBO for Index Buffer %p\n", object);
345 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
346 * restored on the next draw
348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
350 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
351 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
352 ENTER_GL();
354 while(glGetError());
356 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
357 error = glGetError();
358 if(error != GL_NO_ERROR || object->vbo == 0) {
359 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
360 goto out;
363 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
364 error = glGetError();
365 if(error != GL_NO_ERROR) {
366 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
367 goto out;
370 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
371 * copy no readback will be needed
373 glUsage = GL_STATIC_DRAW_ARB;
374 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
375 error = glGetError();
376 if(error != GL_NO_ERROR) {
377 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
378 goto out;
380 LEAVE_GL();
381 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
382 return;
384 out:
385 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
386 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
387 LEAVE_GL();
388 object->vbo = 0;
391 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
392 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
393 HANDLE *sharedHandle, IUnknown *parent) {
394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
395 IWineD3DIndexBufferImpl *object;
396 TRACE("(%p) Creating index buffer\n", This);
398 /* Allocate the storage for the device */
399 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
401 if (Pool == WINED3DPOOL_DEFAULT ) { /* We need a local copy for drawStridedSlow */
402 object->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,object->resource.size);
405 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
406 CreateIndexBufferVBO(This, object);
409 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
410 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
411 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
413 return WINED3D_OK;
416 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
419 IWineD3DStateBlockImpl *object;
420 int i, j;
421 HRESULT temp_result;
423 D3DCREATEOBJECTINSTANCE(object, StateBlock)
424 object->blockType = Type;
426 for(i = 0; i < LIGHTMAP_SIZE; i++) {
427 list_init(&object->lightMap[i]);
430 /* Special case - Used during initialization to produce a placeholder stateblock
431 so other functions called can update a state block */
432 if (Type == WINED3DSBT_INIT) {
433 /* Don't bother increasing the reference count otherwise a device will never
434 be freed due to circular dependencies */
435 return WINED3D_OK;
438 temp_result = allocate_shader_constants(object);
439 if (WINED3D_OK != temp_result)
440 return temp_result;
442 /* Otherwise, might as well set the whole state block to the appropriate values */
443 if (This->stateBlock != NULL)
444 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
445 else
446 memset(object->streamFreq, 1, sizeof(object->streamFreq));
448 /* Reset the ref and type after kludging it */
449 object->wineD3DDevice = This;
450 object->ref = 1;
451 object->blockType = Type;
453 TRACE("Updating changed flags appropriate for type %d\n", Type);
455 if (Type == WINED3DSBT_ALL) {
457 TRACE("ALL => Pretend everything has changed\n");
458 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
460 /* Lights are not part of the changed / set structure */
461 for(j = 0; j < LIGHTMAP_SIZE; j++) {
462 struct list *e;
463 LIST_FOR_EACH(e, &object->lightMap[j]) {
464 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
465 light->changed = TRUE;
466 light->enabledChanged = TRUE;
469 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
470 object->contained_render_states[j - 1] = j;
472 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
473 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
474 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
475 object->contained_transform_states[j - 1] = j;
477 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
478 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
479 object->contained_vs_consts_f[j] = j;
481 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
482 for(j = 0; j < MAX_CONST_I; j++) {
483 object->contained_vs_consts_i[j] = j;
485 object->num_contained_vs_consts_i = MAX_CONST_I;
486 for(j = 0; j < MAX_CONST_B; j++) {
487 object->contained_vs_consts_b[j] = j;
489 object->num_contained_vs_consts_b = MAX_CONST_B;
490 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
491 object->contained_ps_consts_f[j] = j;
493 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
494 for(j = 0; j < MAX_CONST_I; j++) {
495 object->contained_ps_consts_i[j] = j;
497 object->num_contained_ps_consts_i = MAX_CONST_I;
498 for(j = 0; j < MAX_CONST_B; j++) {
499 object->contained_ps_consts_b[j] = j;
501 object->num_contained_ps_consts_b = MAX_CONST_B;
502 for(i = 0; i < MAX_TEXTURES; i++) {
503 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
504 object->contained_tss_states[object->num_contained_tss_states].stage = i;
505 object->contained_tss_states[object->num_contained_tss_states].state = j;
506 object->num_contained_tss_states++;
509 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
510 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
511 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
512 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
513 object->num_contained_sampler_states++;
517 } else if (Type == WINED3DSBT_PIXELSTATE) {
519 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
520 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
522 object->changed.pixelShader = TRUE;
524 /* Pixel Shader Constants */
525 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
526 object->contained_ps_consts_f[i] = i;
527 object->changed.pixelShaderConstantsF[i] = TRUE;
529 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
530 for (i = 0; i < MAX_CONST_B; ++i) {
531 object->contained_ps_consts_b[i] = i;
532 object->changed.pixelShaderConstantsB[i] = TRUE;
534 object->num_contained_ps_consts_b = MAX_CONST_B;
535 for (i = 0; i < MAX_CONST_I; ++i) {
536 object->contained_ps_consts_i[i] = i;
537 object->changed.pixelShaderConstantsI[i] = TRUE;
539 object->num_contained_ps_consts_i = MAX_CONST_I;
541 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
542 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
543 object->contained_render_states[i] = SavedPixelStates_R[i];
545 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
546 for (j = 0; j < MAX_TEXTURES; j++) {
547 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
548 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
549 object->contained_tss_states[object->num_contained_tss_states].stage = j;
550 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
551 object->num_contained_tss_states++;
554 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
555 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
556 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
557 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
558 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
559 object->num_contained_sampler_states++;
563 } else if (Type == WINED3DSBT_VERTEXSTATE) {
565 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
566 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
568 object->changed.vertexShader = TRUE;
570 /* Vertex Shader Constants */
571 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
572 object->changed.vertexShaderConstantsF[i] = TRUE;
573 object->contained_vs_consts_f[i] = i;
575 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
576 for (i = 0; i < MAX_CONST_B; ++i) {
577 object->changed.vertexShaderConstantsB[i] = TRUE;
578 object->contained_vs_consts_b[i] = i;
580 object->num_contained_vs_consts_b = MAX_CONST_B;
581 for (i = 0; i < MAX_CONST_I; ++i) {
582 object->changed.vertexShaderConstantsI[i] = TRUE;
583 object->contained_vs_consts_i[i] = i;
585 object->num_contained_vs_consts_i = MAX_CONST_I;
586 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
587 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
588 object->contained_render_states[i] = SavedVertexStates_R[i];
590 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
591 for (j = 0; j < MAX_TEXTURES; j++) {
592 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
593 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
594 object->contained_tss_states[object->num_contained_tss_states].stage = j;
595 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
596 object->num_contained_tss_states++;
599 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
600 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
601 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
602 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
603 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
604 object->num_contained_sampler_states++;
608 for(j = 0; j < LIGHTMAP_SIZE; j++) {
609 struct list *e;
610 LIST_FOR_EACH(e, &object->lightMap[j]) {
611 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
612 light->changed = TRUE;
613 light->enabledChanged = TRUE;
616 } else {
617 FIXME("Unrecognized state block type %d\n", Type);
620 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
621 return WINED3D_OK;
624 /* ************************************
625 MSDN:
626 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
628 Discard
629 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
631 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
633 ******************************** */
635 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
637 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
638 unsigned int Size = 1;
639 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
640 TRACE("(%p) Create surface\n",This);
642 /** FIXME: Check ranges on the inputs are valid
643 * MSDN
644 * MultisampleQuality
645 * [in] Quality level. The valid range is between zero and one less than the level
646 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
647 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
648 * values of paired render targets, depth stencil surfaces, and the MultiSample type
649 * must all match.
650 *******************************/
654 * TODO: Discard MSDN
655 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
657 * If this flag is set, the contents of the depth stencil buffer will be
658 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
659 * with a different depth surface.
661 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
662 ***************************/
664 if(MultisampleQuality < 0) {
665 FIXME("Invalid multisample level %d\n", MultisampleQuality);
666 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
669 if(MultisampleQuality > 0) {
670 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
671 MultisampleQuality=0;
674 /** FIXME: Check that the format is supported
675 * by the device.
676 *******************************/
678 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
679 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
680 * space!
681 *********************************/
682 if (WINED3DFMT_UNKNOWN == Format) {
683 Size = 0;
684 } else if (Format == WINED3DFMT_DXT1) {
685 /* DXT1 is half byte per pixel */
686 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
688 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
689 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
690 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
691 } else {
692 /* The pitch is a multiple of 4 bytes */
693 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
694 Size *= Height;
697 /** Create and initialise the surface resource **/
698 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
699 /* "Standalone" surface */
700 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
702 object->currentDesc.Width = Width;
703 object->currentDesc.Height = Height;
704 object->currentDesc.MultiSampleType = MultiSample;
705 object->currentDesc.MultiSampleQuality = MultisampleQuality;
706 object->glDescription.level = Level;
708 /* Flags */
709 object->Flags = 0;
710 object->Flags |= Discard ? SFLAG_DISCARD : 0;
711 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
712 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
715 if (WINED3DFMT_UNKNOWN != Format) {
716 object->bytesPerPixel = tableEntry->bpp;
717 } else {
718 object->bytesPerPixel = 0;
721 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
723 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
725 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
726 * this function is too deep to need to care about things like this.
727 * Levels need to be checked too, and possibly Type since they all affect what can be done.
728 * ****************************************/
729 switch(Pool) {
730 case WINED3DPOOL_SCRATCH:
731 if(!Lockable)
732 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
733 "which are mutually exclusive, setting lockable to TRUE\n");
734 Lockable = TRUE;
735 break;
736 case WINED3DPOOL_SYSTEMMEM:
737 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
738 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
739 case WINED3DPOOL_MANAGED:
740 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
741 "Usage of DYNAMIC which are mutually exclusive, not doing "
742 "anything just telling you.\n");
743 break;
744 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
745 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
746 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
747 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
748 break;
749 default:
750 FIXME("(%p) Unknown pool %d\n", This, Pool);
751 break;
754 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
755 FIXME("Trying to create a render target that isn't in the default pool\n");
758 /* mark the texture as dirty so that it gets loaded first time around*/
759 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
760 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
761 This, Width, Height, Format, debug_d3dformat(Format),
762 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
764 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
765 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
766 This->ddraw_primary = (IWineD3DSurface *) object;
768 /* Look at the implementation and set the correct Vtable */
769 switch(Impl) {
770 case SURFACE_OPENGL:
771 /* Check if a 3D adapter is available when creating gl surfaces */
772 if(!This->adapter) {
773 ERR("OpenGL surfaces are not available without opengl\n");
774 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
775 HeapFree(GetProcessHeap(), 0, object);
776 return WINED3DERR_NOTAVAILABLE;
778 break;
780 case SURFACE_GDI:
781 object->lpVtbl = &IWineGDISurface_Vtbl;
782 break;
784 default:
785 /* To be sure to catch this */
786 ERR("Unknown requested surface implementation %d!\n", Impl);
787 IWineD3DSurface_Release((IWineD3DSurface *) object);
788 return WINED3DERR_INVALIDCALL;
791 list_init(&object->renderbuffers);
793 /* Call the private setup routine */
794 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
798 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
799 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
800 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
801 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
804 IWineD3DTextureImpl *object;
805 unsigned int i;
806 UINT tmpW;
807 UINT tmpH;
808 HRESULT hr;
809 unsigned int pow2Width;
810 unsigned int pow2Height;
813 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
814 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
815 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
817 /* TODO: It should only be possible to create textures for formats
818 that are reported as supported */
819 if (WINED3DFMT_UNKNOWN >= Format) {
820 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
821 return WINED3DERR_INVALIDCALL;
824 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
825 D3DINITIALIZEBASETEXTURE(object->baseTexture);
826 object->width = Width;
827 object->height = Height;
829 /** Non-power2 support **/
830 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
831 pow2Width = Width;
832 pow2Height = Height;
833 } else {
834 /* Find the nearest pow2 match */
835 pow2Width = pow2Height = 1;
836 while (pow2Width < Width) pow2Width <<= 1;
837 while (pow2Height < Height) pow2Height <<= 1;
840 /** FIXME: add support for real non-power-two if it's provided by the video card **/
841 /* Precalculated scaling for 'faked' non power of two texture coords */
842 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
843 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
844 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
846 /* Calculate levels for mip mapping */
847 if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
850 tmpW = Width;
851 tmpH = Height;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
861 tmpW = Width;
862 tmpH = Height;
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
869 /* clean up */
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
873 *ppTexture = NULL;
874 return hr;
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
884 TRACE("(%p) : Created texture %p\n", This, object);
885 return WINED3D_OK;
888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
889 UINT Width, UINT Height, UINT Depth,
890 UINT Levels, DWORD Usage,
891 WINED3DFORMAT Format, WINED3DPOOL Pool,
892 IWineD3DVolumeTexture **ppVolumeTexture,
893 HANDLE *pSharedHandle, IUnknown *parent,
894 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
897 IWineD3DVolumeTextureImpl *object;
898 unsigned int i;
899 UINT tmpW;
900 UINT tmpH;
901 UINT tmpD;
903 /* TODO: It should only be possible to create textures for formats
904 that are reported as supported */
905 if (WINED3DFMT_UNKNOWN >= Format) {
906 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
907 return WINED3DERR_INVALIDCALL;
910 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
911 D3DINITIALIZEBASETEXTURE(object->baseTexture);
913 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
914 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
916 object->width = Width;
917 object->height = Height;
918 object->depth = Depth;
920 /* Calculate levels for mip mapping */
921 if (Levels == 0) {
922 object->baseTexture.levels++;
923 tmpW = Width;
924 tmpH = Height;
925 tmpD = Depth;
926 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
927 tmpW = max(1, tmpW >> 1);
928 tmpH = max(1, tmpH >> 1);
929 tmpD = max(1, tmpD >> 1);
930 object->baseTexture.levels++;
932 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
935 /* Generate all the surfaces */
936 tmpW = Width;
937 tmpH = Height;
938 tmpD = Depth;
940 for (i = 0; i < object->baseTexture.levels; i++)
942 HRESULT hr;
943 /* Create the volume */
944 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
945 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
947 if(FAILED(hr)) {
948 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
949 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
950 *ppVolumeTexture = NULL;
951 return hr;
954 /* Set its container to this object */
955 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
957 /* calcualte the next mipmap level */
958 tmpW = max(1, tmpW >> 1);
959 tmpH = max(1, tmpH >> 1);
960 tmpD = max(1, tmpD >> 1);
963 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
964 TRACE("(%p) : Created volume texture %p\n", This, object);
965 return WINED3D_OK;
968 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
969 UINT Width, UINT Height, UINT Depth,
970 DWORD Usage,
971 WINED3DFORMAT Format, WINED3DPOOL Pool,
972 IWineD3DVolume** ppVolume,
973 HANDLE* pSharedHandle, IUnknown *parent) {
975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
976 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
977 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
979 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
981 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
982 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
984 object->currentDesc.Width = Width;
985 object->currentDesc.Height = Height;
986 object->currentDesc.Depth = Depth;
987 object->bytesPerPixel = formatDesc->bpp;
989 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
990 object->lockable = TRUE;
991 object->locked = FALSE;
992 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
993 object->dirty = TRUE;
995 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
998 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
999 UINT Levels, DWORD Usage,
1000 WINED3DFORMAT Format, WINED3DPOOL Pool,
1001 IWineD3DCubeTexture **ppCubeTexture,
1002 HANDLE *pSharedHandle, IUnknown *parent,
1003 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1006 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1007 unsigned int i, j;
1008 UINT tmpW;
1009 HRESULT hr;
1010 unsigned int pow2EdgeLength = EdgeLength;
1012 /* TODO: It should only be possible to create textures for formats
1013 that are reported as supported */
1014 if (WINED3DFMT_UNKNOWN >= Format) {
1015 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1016 return WINED3DERR_INVALIDCALL;
1019 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1020 WARN("(%p) : Tried to create not supported cube texture\n", This);
1021 return WINED3DERR_INVALIDCALL;
1024 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1025 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1027 TRACE("(%p) Create Cube Texture\n", This);
1029 /** Non-power2 support **/
1031 /* Find the nearest pow2 match */
1032 pow2EdgeLength = 1;
1033 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1035 object->edgeLength = EdgeLength;
1036 /* TODO: support for native non-power 2 */
1037 /* Precalculated scaling for 'faked' non power of two texture coords */
1038 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1040 /* Calculate levels for mip mapping */
1041 if (Levels == 0) {
1042 object->baseTexture.levels++;
1043 tmpW = EdgeLength;
1044 while (tmpW > 1) {
1045 tmpW = max(1, tmpW >> 1);
1046 object->baseTexture.levels++;
1048 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1051 /* Generate all the surfaces */
1052 tmpW = EdgeLength;
1053 for (i = 0; i < object->baseTexture.levels; i++) {
1055 /* Create the 6 faces */
1056 for (j = 0; j < 6; j++) {
1058 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1059 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1061 if(hr!= WINED3D_OK) {
1062 /* clean up */
1063 int k;
1064 int l;
1065 for (l = 0; l < j; l++) {
1066 IWineD3DSurface_Release(object->surfaces[j][i]);
1068 for (k = 0; k < i; k++) {
1069 for (l = 0; l < 6; l++) {
1070 IWineD3DSurface_Release(object->surfaces[l][j]);
1074 FIXME("(%p) Failed to create surface\n",object);
1075 HeapFree(GetProcessHeap(),0,object);
1076 *ppCubeTexture = NULL;
1077 return hr;
1079 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1080 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1082 tmpW = max(1, tmpW >> 1);
1085 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1086 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1087 return WINED3D_OK;
1090 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1092 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1093 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1095 /* Just a check to see if we support this type of query */
1096 switch(Type) {
1097 case WINED3DQUERYTYPE_OCCLUSION:
1098 TRACE("(%p) occlusion query\n", This);
1099 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1100 hr = WINED3D_OK;
1101 else
1102 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1103 break;
1105 case WINED3DQUERYTYPE_EVENT:
1106 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1107 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1108 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1110 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1112 hr = WINED3D_OK;
1113 break;
1115 case WINED3DQUERYTYPE_VCACHE:
1116 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1117 case WINED3DQUERYTYPE_VERTEXSTATS:
1118 case WINED3DQUERYTYPE_TIMESTAMP:
1119 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1120 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1121 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1122 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1123 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1124 case WINED3DQUERYTYPE_PIXELTIMINGS:
1125 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1126 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1127 default:
1128 FIXME("(%p) Unhandled query type %d\n", This, Type);
1130 if(NULL == ppQuery || hr != WINED3D_OK) {
1131 return hr;
1134 D3DCREATEOBJECTINSTANCE(object, Query)
1135 object->type = Type;
1136 /* allocated the 'extended' data based on the type of query requested */
1137 switch(Type){
1138 case WINED3DQUERYTYPE_OCCLUSION:
1139 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1140 TRACE("(%p) Allocating data for an occlusion query\n", This);
1141 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1142 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1143 break;
1145 case WINED3DQUERYTYPE_EVENT:
1146 /* TODO: GL_APPLE_fence */
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 } else if(GL_SUPPORT(NV_FENCE)) {
1152 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1153 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1154 checkGLcall("glGenFencesNV");
1156 break;
1158 case WINED3DQUERYTYPE_VCACHE:
1159 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1160 case WINED3DQUERYTYPE_VERTEXSTATS:
1161 case WINED3DQUERYTYPE_TIMESTAMP:
1162 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1163 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1164 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1165 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1166 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1167 case WINED3DQUERYTYPE_PIXELTIMINGS:
1168 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1169 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1170 default:
1171 object->extendedData = 0;
1172 FIXME("(%p) Unhandled query type %d\n",This , Type);
1174 TRACE("(%p) : Created Query %p\n", This, object);
1175 return WINED3D_OK;
1178 /*****************************************************************************
1179 * IWineD3DDeviceImpl_SetupFullscreenWindow
1181 * Helper function that modifies a HWND's Style and ExStyle for proper
1182 * fullscreen use.
1184 * Params:
1185 * iface: Pointer to the IWineD3DDevice interface
1186 * window: Window to setup
1188 *****************************************************************************/
1189 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1192 LONG style, exStyle;
1193 /* Don't do anything if an original style is stored.
1194 * That shouldn't happen
1196 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1197 if (This->style || This->exStyle) {
1198 ERR("(%p): Want to change the window parameters of HWND %p, but "
1199 "another style is stored for restoration afterwards\n", This, window);
1202 /* Get the parameters and save them */
1203 style = GetWindowLongW(window, GWL_STYLE);
1204 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1205 This->style = style;
1206 This->exStyle = exStyle;
1208 /* Filter out window decorations */
1209 style &= ~WS_CAPTION;
1210 style &= ~WS_THICKFRAME;
1211 exStyle &= ~WS_EX_WINDOWEDGE;
1212 exStyle &= ~WS_EX_CLIENTEDGE;
1214 /* Make sure the window is managed, otherwise we won't get keyboard input */
1215 style |= WS_POPUP | WS_SYSMENU;
1217 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1218 This->style, This->exStyle, style, exStyle);
1220 SetWindowLongW(window, GWL_STYLE, style);
1221 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1223 /* Inform the window about the update. */
1224 SetWindowPos(window, HWND_TOP, 0, 0,
1225 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1226 ShowWindow(window, SW_NORMAL);
1229 /*****************************************************************************
1230 * IWineD3DDeviceImpl_RestoreWindow
1232 * Helper function that restores a windows' properties when taking it out
1233 * of fullscreen mode
1235 * Params:
1236 * iface: Pointer to the IWineD3DDevice interface
1237 * window: Window to setup
1239 *****************************************************************************/
1240 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1243 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1244 * switch, do nothing
1246 if (!This->style && !This->exStyle) return;
1248 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1249 This, window, This->style, This->exStyle);
1251 SetWindowLongW(window, GWL_STYLE, This->style);
1252 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1254 /* Delete the old values */
1255 This->style = 0;
1256 This->exStyle = 0;
1258 /* Inform the window about the update */
1259 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1260 0, 0, 0, 0, /* Pos, Size, ignored */
1261 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1264 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1265 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1266 IUnknown* parent,
1267 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1268 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1271 HDC hDc;
1272 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1273 HRESULT hr = WINED3D_OK;
1274 IUnknown *bufferParent;
1276 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1278 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1279 * does a device hold a reference to a swap chain giving them a lifetime of the device
1280 * or does the swap chain notify the device of its destruction.
1281 *******************************/
1283 /* Check the params */
1284 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1285 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1286 return WINED3DERR_INVALIDCALL;
1287 } else if (pPresentationParameters->BackBufferCount > 1) {
1288 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");
1291 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1293 /*********************
1294 * Lookup the window Handle and the relating X window handle
1295 ********************/
1297 /* Setup hwnd we are using, plus which display this equates to */
1298 object->win_handle = pPresentationParameters->hDeviceWindow;
1299 if (!object->win_handle) {
1300 object->win_handle = This->createParms.hFocusWindow;
1303 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1304 hDc = GetDC(object->win_handle);
1305 TRACE("Using hDc %p\n", hDc);
1307 if (NULL == hDc) {
1308 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1309 return WINED3DERR_NOTAVAILABLE;
1312 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1313 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1314 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1315 ReleaseDC(object->win_handle, hDc);
1317 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1318 * then the corresponding dimension of the client area of the hDeviceWindow
1319 * (or the focus window, if hDeviceWindow is NULL) is taken.
1320 **********************/
1322 if (pPresentationParameters->Windowed &&
1323 ((pPresentationParameters->BackBufferWidth == 0) ||
1324 (pPresentationParameters->BackBufferHeight == 0))) {
1326 RECT Rect;
1327 GetClientRect(object->win_handle, &Rect);
1329 if (pPresentationParameters->BackBufferWidth == 0) {
1330 pPresentationParameters->BackBufferWidth = Rect.right;
1331 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1333 if (pPresentationParameters->BackBufferHeight == 0) {
1334 pPresentationParameters->BackBufferHeight = Rect.bottom;
1335 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1339 /* Put the correct figures in the presentation parameters */
1340 TRACE("Copying across presentation parameters\n");
1341 object->presentParms = *pPresentationParameters;
1343 TRACE("calling rendertarget CB\n");
1344 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1345 parent,
1346 object->presentParms.BackBufferWidth,
1347 object->presentParms.BackBufferHeight,
1348 object->presentParms.BackBufferFormat,
1349 object->presentParms.MultiSampleType,
1350 object->presentParms.MultiSampleQuality,
1351 TRUE /* Lockable */,
1352 &object->frontBuffer,
1353 NULL /* pShared (always null)*/);
1354 if (object->frontBuffer != NULL) {
1355 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1356 } else {
1357 ERR("Failed to create the front buffer\n");
1358 goto error;
1362 * Create an opengl context for the display visual
1363 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1364 * use different properties after that point in time. FIXME: How to handle when requested format
1365 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1366 * it chooses is identical to the one already being used!
1367 **********************************/
1368 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1370 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1371 if(!object->context)
1372 return E_OUTOFMEMORY;
1373 object->num_contexts = 1;
1375 ENTER_GL();
1376 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1377 LEAVE_GL();
1379 if (!object->context[0]) {
1380 ERR("Failed to create a new context\n");
1381 hr = WINED3DERR_NOTAVAILABLE;
1382 goto error;
1383 } else {
1384 TRACE("Context created (HWND=%p, glContext=%p)\n",
1385 object->win_handle, object->context[0]->glCtx);
1388 /*********************
1389 * Windowed / Fullscreen
1390 *******************/
1393 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1394 * so we should really check to see if there is a fullscreen swapchain already
1395 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1396 **************************************/
1398 if (!pPresentationParameters->Windowed) {
1400 DEVMODEW devmode;
1401 HDC hdc;
1402 int bpp = 0;
1403 RECT clip_rc;
1405 /* Get info on the current display setup */
1406 hdc = GetDC(0);
1407 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1408 ReleaseDC(0, hdc);
1410 /* Change the display settings */
1411 memset(&devmode, 0, sizeof(devmode));
1412 devmode.dmSize = sizeof(devmode);
1413 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1414 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1415 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1416 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1417 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1419 /* For GetDisplayMode */
1420 This->ddraw_width = devmode.dmPelsWidth;
1421 This->ddraw_height = devmode.dmPelsHeight;
1422 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1424 IWineD3DDevice_SetFullscreen(iface, TRUE);
1426 /* And finally clip mouse to our screen */
1427 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1428 ClipCursor(&clip_rc);
1431 /*********************
1432 * Create the back, front and stencil buffers
1433 *******************/
1434 if(object->presentParms.BackBufferCount > 0) {
1435 int i;
1437 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1438 if(!object->backBuffer) {
1439 ERR("Out of memory\n");
1440 hr = E_OUTOFMEMORY;
1441 goto error;
1444 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1445 TRACE("calling rendertarget CB\n");
1446 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1447 parent,
1448 object->presentParms.BackBufferWidth,
1449 object->presentParms.BackBufferHeight,
1450 object->presentParms.BackBufferFormat,
1451 object->presentParms.MultiSampleType,
1452 object->presentParms.MultiSampleQuality,
1453 TRUE /* Lockable */,
1454 &object->backBuffer[i],
1455 NULL /* pShared (always null)*/);
1456 if(hr == WINED3D_OK && object->backBuffer[i]) {
1457 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1458 } else {
1459 ERR("Cannot create new back buffer\n");
1460 goto error;
1462 ENTER_GL();
1463 glDrawBuffer(GL_BACK);
1464 checkGLcall("glDrawBuffer(GL_BACK)");
1465 LEAVE_GL();
1467 } else {
1468 object->backBuffer = NULL;
1470 /* Single buffering - draw to front buffer */
1471 ENTER_GL();
1472 glDrawBuffer(GL_FRONT);
1473 checkGLcall("glDrawBuffer(GL_FRONT)");
1474 LEAVE_GL();
1477 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1478 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1479 TRACE("Creating depth stencil buffer\n");
1480 if (This->depthStencilBuffer == NULL ) {
1481 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1482 parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.AutoDepthStencilFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 FALSE /* FIXME: Discard */,
1489 &This->depthStencilBuffer,
1490 NULL /* pShared (always null)*/ );
1491 if (This->depthStencilBuffer != NULL)
1492 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1495 /** TODO: A check on width, height and multisample types
1496 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1497 ****************************/
1498 object->wantsDepthStencilBuffer = TRUE;
1499 } else {
1500 object->wantsDepthStencilBuffer = FALSE;
1503 TRACE("Created swapchain %p\n", object);
1504 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1505 return WINED3D_OK;
1507 error:
1508 if (object->backBuffer) {
1509 int i;
1510 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1511 if(object->backBuffer[i]) {
1512 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1513 IUnknown_Release(bufferParent); /* once for the get parent */
1514 if (IUnknown_Release(bufferParent) > 0) {
1515 FIXME("(%p) Something's still holding the back buffer\n",This);
1519 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1520 object->backBuffer = NULL;
1522 if(object->context[0])
1523 DestroyContext(This, object->context[0]);
1524 if(object->frontBuffer) {
1525 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1526 IUnknown_Release(bufferParent); /* once for the get parent */
1527 if (IUnknown_Release(bufferParent) > 0) {
1528 FIXME("(%p) Something's still holding the front buffer\n",This);
1531 HeapFree(GetProcessHeap(), 0, object);
1532 return hr;
1535 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1536 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1538 TRACE("(%p)\n", This);
1540 return This->NumberOfSwapChains;
1543 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1545 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1547 if(iSwapChain < This->NumberOfSwapChains) {
1548 *pSwapChain = This->swapchains[iSwapChain];
1549 IWineD3DSwapChain_AddRef(*pSwapChain);
1550 TRACE("(%p) returning %p\n", This, *pSwapChain);
1551 return WINED3D_OK;
1552 } else {
1553 TRACE("Swapchain out of range\n");
1554 *pSwapChain = NULL;
1555 return WINED3DERR_INVALIDCALL;
1559 /*****
1560 * Vertex Declaration
1561 *****/
1562 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1563 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1565 IWineD3DVertexDeclarationImpl *object = NULL;
1566 HRESULT hr = WINED3D_OK;
1568 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1569 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1571 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1573 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1575 return hr;
1578 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1580 unsigned int idx, idx2;
1581 unsigned int offset;
1582 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1583 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1584 BOOL has_blend_idx = has_blend &&
1585 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1586 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1587 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1588 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1589 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1590 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1591 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1593 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1594 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1596 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1597 WINED3DVERTEXELEMENT *elements = NULL;
1599 unsigned int size;
1600 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1601 if (has_blend_idx) num_blends--;
1603 /* Compute declaration size */
1604 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1605 has_psize + has_diffuse + has_specular + num_textures + 1;
1607 /* convert the declaration */
1608 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1609 if (!elements)
1610 return 0;
1612 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1613 idx = 0;
1614 if (has_pos) {
1615 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1616 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1617 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1619 else {
1620 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1621 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1623 elements[idx].UsageIndex = 0;
1624 idx++;
1626 if (has_blend && (num_blends > 0)) {
1627 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1628 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1629 else
1630 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1631 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1632 elements[idx].UsageIndex = 0;
1633 idx++;
1635 if (has_blend_idx) {
1636 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1637 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1638 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1639 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1640 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1641 else
1642 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1643 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1644 elements[idx].UsageIndex = 0;
1645 idx++;
1647 if (has_normal) {
1648 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1649 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1650 elements[idx].UsageIndex = 0;
1651 idx++;
1653 if (has_psize) {
1654 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1655 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1656 elements[idx].UsageIndex = 0;
1657 idx++;
1659 if (has_diffuse) {
1660 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1661 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1662 elements[idx].UsageIndex = 0;
1663 idx++;
1665 if (has_specular) {
1666 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1667 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1668 elements[idx].UsageIndex = 1;
1669 idx++;
1671 for (idx2 = 0; idx2 < num_textures; idx2++) {
1672 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1673 switch (numcoords) {
1674 case WINED3DFVF_TEXTUREFORMAT1:
1675 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1676 break;
1677 case WINED3DFVF_TEXTUREFORMAT2:
1678 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1679 break;
1680 case WINED3DFVF_TEXTUREFORMAT3:
1681 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1682 break;
1683 case WINED3DFVF_TEXTUREFORMAT4:
1684 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1685 break;
1687 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1688 elements[idx].UsageIndex = idx2;
1689 idx++;
1692 /* Now compute offsets, and initialize the rest of the fields */
1693 for (idx = 0, offset = 0; idx < size-1; idx++) {
1694 elements[idx].Stream = 0;
1695 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1696 elements[idx].Offset = offset;
1697 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1700 *ppVertexElements = elements;
1701 return size;
1704 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1705 WINED3DVERTEXELEMENT* elements = NULL;
1706 size_t size;
1707 DWORD hr;
1709 size = ConvertFvfToDeclaration(Fvf, &elements);
1710 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1712 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1713 HeapFree(GetProcessHeap(), 0, elements);
1714 if (hr != S_OK) return hr;
1716 return WINED3D_OK;
1719 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1720 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1722 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1723 HRESULT hr = WINED3D_OK;
1724 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1725 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1727 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1729 if (vertex_declaration) {
1730 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1733 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1735 if (WINED3D_OK != hr) {
1736 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1737 IWineD3DVertexShader_Release(*ppVertexShader);
1738 return WINED3DERR_INVALIDCALL;
1741 return WINED3D_OK;
1744 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1746 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1747 HRESULT hr = WINED3D_OK;
1749 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1750 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1751 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1752 if (WINED3D_OK == hr) {
1753 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1754 } else {
1755 WARN("(%p) : Failed to create pixel shader\n", This);
1758 return hr;
1761 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1763 IWineD3DPaletteImpl *object;
1764 HRESULT hr;
1765 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1767 /* Create the new object */
1768 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1769 if(!object) {
1770 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1771 return E_OUTOFMEMORY;
1774 object->lpVtbl = &IWineD3DPalette_Vtbl;
1775 object->ref = 1;
1776 object->Flags = Flags;
1777 object->parent = Parent;
1778 object->wineD3DDevice = This;
1779 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1781 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1783 if(!object->hpal) {
1784 HeapFree( GetProcessHeap(), 0, object);
1785 return E_OUTOFMEMORY;
1788 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1789 if(FAILED(hr)) {
1790 IWineD3DPalette_Release((IWineD3DPalette *) object);
1791 return hr;
1794 *Palette = (IWineD3DPalette *) object;
1796 return WINED3D_OK;
1799 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1801 IWineD3DSwapChainImpl *swapchain;
1802 HRESULT hr;
1803 DWORD state;
1805 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1806 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1808 /* TODO: Test if OpenGL is compiled in and loaded */
1810 TRACE("(%p) : Creating stateblock\n", This);
1811 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1812 hr = IWineD3DDevice_CreateStateBlock(iface,
1813 WINED3DSBT_INIT,
1814 (IWineD3DStateBlock **)&This->stateBlock,
1815 NULL);
1816 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1817 WARN("Failed to create stateblock\n");
1818 return hr;
1820 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1821 This->updateStateBlock = This->stateBlock;
1822 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1824 hr = allocate_shader_constants(This->updateStateBlock);
1825 if (WINED3D_OK != hr)
1826 return hr;
1828 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1829 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1830 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1832 /* Initialize the texture unit mapping to a 1:1 mapping */
1833 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1834 if (state < GL_LIMITS(fragment_samplers)) {
1835 This->texUnitMap[state] = state;
1836 This->rev_tex_unit_map[state] = state;
1837 } else {
1838 This->texUnitMap[state] = -1;
1839 This->rev_tex_unit_map[state] = -1;
1843 /* Setup the implicit swapchain */
1844 TRACE("Creating implicit swapchain\n");
1845 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1846 if (FAILED(hr) || !swapchain) {
1847 WARN("Failed to create implicit swapchain\n");
1848 return hr;
1851 This->NumberOfSwapChains = 1;
1852 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1853 if(!This->swapchains) {
1854 ERR("Out of memory!\n");
1855 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1856 return E_OUTOFMEMORY;
1858 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1860 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1862 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1863 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1864 This->render_targets[0] = swapchain->backBuffer[0];
1865 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1867 else {
1868 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1869 This->render_targets[0] = swapchain->frontBuffer;
1870 This->lastActiveRenderTarget = swapchain->frontBuffer;
1872 IWineD3DSurface_AddRef(This->render_targets[0]);
1873 This->activeContext = swapchain->context[0];
1874 This->lastThread = GetCurrentThreadId();
1876 /* Depth Stencil support */
1877 This->stencilBufferTarget = This->depthStencilBuffer;
1878 if (NULL != This->stencilBufferTarget) {
1879 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1882 /* Set up some starting GL setup */
1883 ENTER_GL();
1885 /* Setup all the devices defaults */
1886 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1887 #if 0
1888 IWineD3DImpl_CheckGraphicsMemory();
1889 #endif
1891 { /* Set a default viewport */
1892 WINED3DVIEWPORT vp;
1893 vp.X = 0;
1894 vp.Y = 0;
1895 vp.Width = pPresentationParameters->BackBufferWidth;
1896 vp.Height = pPresentationParameters->BackBufferHeight;
1897 vp.MinZ = 0.0f;
1898 vp.MaxZ = 1.0f;
1899 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1902 /* Initialize the current view state */
1903 This->view_ident = 1;
1904 This->contexts[0]->last_was_rhw = 0;
1905 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1906 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1908 switch(wined3d_settings.offscreen_rendering_mode) {
1909 case ORM_FBO:
1910 case ORM_PBUFFER:
1911 This->offscreenBuffer = GL_BACK;
1912 break;
1914 case ORM_BACKBUFFER:
1916 if(GL_LIMITS(aux_buffers) > 0) {
1917 TRACE("Using auxilliary buffer for offscreen rendering\n");
1918 This->offscreenBuffer = GL_AUX0;
1919 } else {
1920 TRACE("Using back buffer for offscreen rendering\n");
1921 This->offscreenBuffer = GL_BACK;
1926 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
1927 LEAVE_GL();
1929 /* Clear the screen */
1930 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
1931 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
1932 0x00, 1.0, 0);
1934 This->d3d_initialized = TRUE;
1935 return WINED3D_OK;
1938 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
1939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1940 int sampler;
1941 UINT i;
1942 TRACE("(%p)\n", This);
1944 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1946 /* I don't think that the interface guarants that the device is destroyed from the same thread
1947 * it was created. Thus make sure a context is active for the glDelete* calls
1949 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1951 TRACE("Deleting high order patches\n");
1952 for(i = 0; i < PATCHMAP_SIZE; i++) {
1953 struct list *e1, *e2;
1954 struct WineD3DRectPatch *patch;
1955 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
1956 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
1957 IWineD3DDevice_DeletePatch(iface, patch->Handle);
1961 /* Delete the pbuffer context if there is any */
1962 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
1964 /* Delete the mouse cursor texture */
1965 if(This->cursorTexture) {
1966 ENTER_GL();
1967 glDeleteTextures(1, &This->cursorTexture);
1968 LEAVE_GL();
1969 This->cursorTexture = 0;
1972 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
1973 IWineD3DDevice_SetTexture(iface, sampler, NULL);
1975 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
1976 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
1979 /* Release the update stateblock */
1980 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
1981 if(This->updateStateBlock != This->stateBlock)
1982 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1984 This->updateStateBlock = NULL;
1986 { /* because were not doing proper internal refcounts releasing the primary state block
1987 causes recursion with the extra checks in ResourceReleased, to avoid this we have
1988 to set this->stateBlock = NULL; first */
1989 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
1990 This->stateBlock = NULL;
1992 /* Release the stateblock */
1993 if(IWineD3DStateBlock_Release(stateBlock) > 0){
1994 FIXME("(%p) Something's still holding the Update stateblock\n",This);
1998 /* Release the buffers (with sanity checks)*/
1999 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2000 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2001 if(This->depthStencilBuffer != This->stencilBufferTarget)
2002 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2004 This->stencilBufferTarget = NULL;
2006 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2007 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2008 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2010 TRACE("Setting rendertarget to NULL\n");
2011 This->render_targets[0] = NULL;
2013 if (This->depthStencilBuffer) {
2014 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2015 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2017 This->depthStencilBuffer = NULL;
2020 for(i=0; i < This->NumberOfSwapChains; i++) {
2021 TRACE("Releasing the implicit swapchain %d\n", i);
2022 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2023 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2027 HeapFree(GetProcessHeap(), 0, This->swapchains);
2028 This->swapchains = NULL;
2029 This->NumberOfSwapChains = 0;
2031 HeapFree(GetProcessHeap(), 0, This->render_targets);
2032 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2033 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2034 This->render_targets = NULL;
2035 This->fbo_color_attachments = NULL;
2036 This->draw_buffers = NULL;
2039 This->d3d_initialized = FALSE;
2040 return WINED3D_OK;
2043 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2045 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2047 /* Setup the window for fullscreen mode */
2048 if(fullscreen && !This->ddraw_fullscreen) {
2049 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2050 } else if(!fullscreen && This->ddraw_fullscreen) {
2051 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2054 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2055 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2056 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2057 * separately.
2059 This->ddraw_fullscreen = fullscreen;
2062 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2063 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2064 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2066 * There is no way to deactivate thread safety once it is enabled
2068 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2071 /*For now just store the flag(needed in case of ddraw) */
2072 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2074 return;
2077 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2078 DEVMODEW devmode;
2079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2080 LONG ret;
2081 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2082 RECT clip_rc;
2084 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2086 /* Resize the screen even without a window:
2087 * The app could have unset it with SetCooperativeLevel, but not called
2088 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2089 * but we don't have any hwnd
2092 memset(&devmode, 0, sizeof(devmode));
2093 devmode.dmSize = sizeof(devmode);
2094 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2095 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2096 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2097 devmode.dmPelsWidth = pMode->Width;
2098 devmode.dmPelsHeight = pMode->Height;
2100 devmode.dmDisplayFrequency = pMode->RefreshRate;
2101 if (pMode->RefreshRate != 0) {
2102 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2105 /* Only change the mode if necessary */
2106 if( (This->ddraw_width == pMode->Width) &&
2107 (This->ddraw_height == pMode->Height) &&
2108 (This->ddraw_format == pMode->Format) &&
2109 (pMode->RefreshRate == 0) ) {
2110 return WINED3D_OK;
2113 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2114 if (ret != DISP_CHANGE_SUCCESSFUL) {
2115 if(devmode.dmDisplayFrequency != 0) {
2116 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2117 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2118 devmode.dmDisplayFrequency = 0;
2119 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2121 if(ret != DISP_CHANGE_SUCCESSFUL) {
2122 return WINED3DERR_NOTAVAILABLE;
2126 /* Store the new values */
2127 This->ddraw_width = pMode->Width;
2128 This->ddraw_height = pMode->Height;
2129 This->ddraw_format = pMode->Format;
2131 /* Only do this with a window of course */
2132 if(This->ddraw_window)
2133 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2135 /* And finally clip mouse to our screen */
2136 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2137 ClipCursor(&clip_rc);
2139 return WINED3D_OK;
2142 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2144 *ppD3D= This->wineD3D;
2145 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2146 IWineD3D_AddRef(*ppD3D);
2147 return WINED3D_OK;
2150 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2151 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2152 * into the video ram as possible and seeing how many fit
2153 * you can also get the correct initial value from nvidia and ATI's driver via X
2154 * texture memory is video memory + AGP memory
2155 *******************/
2156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2157 static BOOL showfixmes = TRUE;
2158 if (showfixmes) {
2159 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2160 (wined3d_settings.emulated_textureram/(1024*1024)),
2161 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2162 showfixmes = FALSE;
2164 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2165 (wined3d_settings.emulated_textureram/(1024*1024)),
2166 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2167 /* return simulated texture memory left */
2168 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2173 /*****
2174 * Get / Set FVF
2175 *****/
2176 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2177 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2179 /* Update the current state block */
2180 This->updateStateBlock->changed.fvf = TRUE;
2182 if(This->updateStateBlock->fvf == fvf) {
2183 TRACE("Application is setting the old fvf over, nothing to do\n");
2184 return WINED3D_OK;
2187 This->updateStateBlock->fvf = fvf;
2188 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2189 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2190 return WINED3D_OK;
2194 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2196 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2197 *pfvf = This->stateBlock->fvf;
2198 return WINED3D_OK;
2201 /*****
2202 * Get / Set Stream Source
2203 *****/
2204 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2206 IWineD3DVertexBuffer *oldSrc;
2208 if (StreamNumber >= MAX_STREAMS) {
2209 WARN("Stream out of range %d\n", StreamNumber);
2210 return WINED3DERR_INVALIDCALL;
2213 oldSrc = This->stateBlock->streamSource[StreamNumber];
2214 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2216 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2218 if(oldSrc == pStreamData &&
2219 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2220 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2221 TRACE("Application is setting the old values over, nothing to do\n");
2222 return WINED3D_OK;
2225 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2226 if (pStreamData) {
2227 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2228 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2231 /* Handle recording of state blocks */
2232 if (This->isRecordingState) {
2233 TRACE("Recording... not performing anything\n");
2234 return WINED3D_OK;
2237 /* Need to do a getParent and pass the reffs up */
2238 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2239 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2240 so for now, just count internally */
2241 if (pStreamData != NULL) {
2242 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2243 InterlockedIncrement(&vbImpl->bindCount);
2244 IWineD3DVertexBuffer_AddRef(pStreamData);
2246 if (oldSrc != NULL) {
2247 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2248 IWineD3DVertexBuffer_Release(oldSrc);
2251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2253 return WINED3D_OK;
2256 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2259 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2260 This->stateBlock->streamSource[StreamNumber],
2261 This->stateBlock->streamOffset[StreamNumber],
2262 This->stateBlock->streamStride[StreamNumber]);
2264 if (StreamNumber >= MAX_STREAMS) {
2265 WARN("Stream out of range %d\n", StreamNumber);
2266 return WINED3DERR_INVALIDCALL;
2268 *pStream = This->stateBlock->streamSource[StreamNumber];
2269 *pStride = This->stateBlock->streamStride[StreamNumber];
2270 if (pOffset) {
2271 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2274 if (*pStream != NULL) {
2275 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2277 return WINED3D_OK;
2280 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2282 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2283 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2285 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2286 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2288 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2289 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2291 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2292 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2296 return WINED3D_OK;
2299 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2302 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2303 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2305 TRACE("(%p) : returning %d\n", This, *Divider);
2307 return WINED3D_OK;
2310 /*****
2311 * Get / Set & Multiply Transform
2312 *****/
2313 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2316 /* Most of this routine, comments included copied from ddraw tree initially: */
2317 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2319 /* Handle recording of state blocks */
2320 if (This->isRecordingState) {
2321 TRACE("Recording... not performing anything\n");
2322 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2323 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2324 return WINED3D_OK;
2328 * If the new matrix is the same as the current one,
2329 * we cut off any further processing. this seems to be a reasonable
2330 * optimization because as was noticed, some apps (warcraft3 for example)
2331 * tend towards setting the same matrix repeatedly for some reason.
2333 * From here on we assume that the new matrix is different, wherever it matters.
2335 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2336 TRACE("The app is setting the same matrix over again\n");
2337 return WINED3D_OK;
2338 } else {
2339 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2343 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2344 where ViewMat = Camera space, WorldMat = world space.
2346 In OpenGL, camera and world space is combined into GL_MODELVIEW
2347 matrix. The Projection matrix stay projection matrix.
2350 /* Capture the times we can just ignore the change for now */
2351 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2352 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2353 /* Handled by the state manager */
2356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2357 return WINED3D_OK;
2360 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2362 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2363 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2364 return WINED3D_OK;
2367 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2368 WINED3DMATRIX *mat = NULL;
2369 WINED3DMATRIX temp;
2371 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2372 * below means it will be recorded in a state block change, but it
2373 * works regardless where it is recorded.
2374 * If this is found to be wrong, change to StateBlock.
2376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2377 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2379 if (State < HIGHEST_TRANSFORMSTATE)
2381 mat = &This->updateStateBlock->transforms[State];
2382 } else {
2383 FIXME("Unhandled transform state!!\n");
2386 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2388 /* Apply change via set transform - will reapply to eg. lights this way */
2389 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2392 /*****
2393 * Get / Set Light
2394 *****/
2395 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2396 you can reference any indexes you want as long as that number max are enabled at any
2397 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2398 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2399 but when recording, just build a chain pretty much of commands to be replayed. */
2401 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2402 float rho;
2403 PLIGHTINFOEL *object = NULL;
2404 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2405 struct list *e;
2407 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2408 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2410 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2411 * the gl driver.
2413 if(!pLight) {
2414 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2415 return WINED3DERR_INVALIDCALL;
2418 switch(pLight->Type) {
2419 case WINED3DLIGHT_POINT:
2420 case WINED3DLIGHT_SPOT:
2421 case WINED3DLIGHT_PARALLELPOINT:
2422 case WINED3DLIGHT_GLSPOT:
2423 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2424 * most wanted
2426 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2427 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2428 return WINED3DERR_INVALIDCALL;
2430 break;
2432 case WINED3DLIGHT_DIRECTIONAL:
2433 /* Ignores attenuation */
2434 break;
2436 default:
2437 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2438 return WINED3DERR_INVALIDCALL;
2441 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2442 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2443 if(object->OriginalIndex == Index) break;
2444 object = NULL;
2447 if(!object) {
2448 TRACE("Adding new light\n");
2449 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2450 if(!object) {
2451 ERR("Out of memory error when allocating a light\n");
2452 return E_OUTOFMEMORY;
2454 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2455 object->glIndex = -1;
2456 object->OriginalIndex = Index;
2457 object->changed = TRUE;
2460 /* Initialize the object */
2461 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,
2462 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2463 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2464 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2465 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2466 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2467 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2469 /* Save away the information */
2470 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2472 switch (pLight->Type) {
2473 case WINED3DLIGHT_POINT:
2474 /* Position */
2475 object->lightPosn[0] = pLight->Position.x;
2476 object->lightPosn[1] = pLight->Position.y;
2477 object->lightPosn[2] = pLight->Position.z;
2478 object->lightPosn[3] = 1.0f;
2479 object->cutoff = 180.0f;
2480 /* FIXME: Range */
2481 break;
2483 case WINED3DLIGHT_DIRECTIONAL:
2484 /* Direction */
2485 object->lightPosn[0] = -pLight->Direction.x;
2486 object->lightPosn[1] = -pLight->Direction.y;
2487 object->lightPosn[2] = -pLight->Direction.z;
2488 object->lightPosn[3] = 0.0;
2489 object->exponent = 0.0f;
2490 object->cutoff = 180.0f;
2491 break;
2493 case WINED3DLIGHT_SPOT:
2494 /* Position */
2495 object->lightPosn[0] = pLight->Position.x;
2496 object->lightPosn[1] = pLight->Position.y;
2497 object->lightPosn[2] = pLight->Position.z;
2498 object->lightPosn[3] = 1.0;
2500 /* Direction */
2501 object->lightDirn[0] = pLight->Direction.x;
2502 object->lightDirn[1] = pLight->Direction.y;
2503 object->lightDirn[2] = pLight->Direction.z;
2504 object->lightDirn[3] = 1.0;
2507 * opengl-ish and d3d-ish spot lights use too different models for the
2508 * light "intensity" as a function of the angle towards the main light direction,
2509 * so we only can approximate very roughly.
2510 * however spot lights are rather rarely used in games (if ever used at all).
2511 * furthermore if still used, probably nobody pays attention to such details.
2513 if (pLight->Falloff == 0) {
2514 rho = 6.28f;
2515 } else {
2516 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2518 if (rho < 0.0001) rho = 0.0001f;
2519 object->exponent = -0.3/log(cos(rho/2));
2520 if (object->exponent > 128.0) {
2521 object->exponent = 128.0;
2523 object->cutoff = pLight->Phi*90/M_PI;
2525 /* FIXME: Range */
2526 break;
2528 default:
2529 FIXME("Unrecognized light type %d\n", pLight->Type);
2532 /* Update the live definitions if the light is currently assigned a glIndex */
2533 if (object->glIndex != -1 && !This->isRecordingState) {
2534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2536 return WINED3D_OK;
2539 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2540 PLIGHTINFOEL *lightInfo = NULL;
2541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2543 struct list *e;
2544 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2546 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2547 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2548 if(lightInfo->OriginalIndex == Index) break;
2549 lightInfo = NULL;
2552 if (lightInfo == NULL) {
2553 TRACE("Light information requested but light not defined\n");
2554 return WINED3DERR_INVALIDCALL;
2557 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2558 return WINED3D_OK;
2561 /*****
2562 * Get / Set Light Enable
2563 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2564 *****/
2565 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2566 PLIGHTINFOEL *lightInfo = NULL;
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2569 struct list *e;
2570 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2572 /* Tests show true = 128...not clear why */
2573 Enable = Enable? 128: 0;
2575 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2576 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2577 if(lightInfo->OriginalIndex == Index) break;
2578 lightInfo = NULL;
2580 TRACE("Found light: %p\n", lightInfo);
2582 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2583 if (lightInfo == NULL) {
2585 TRACE("Light enabled requested but light not defined, so defining one!\n");
2586 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2588 /* Search for it again! Should be fairly quick as near head of list */
2589 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2590 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2591 if(lightInfo->OriginalIndex == Index) break;
2592 lightInfo = NULL;
2594 if (lightInfo == NULL) {
2595 FIXME("Adding default lights has failed dismally\n");
2596 return WINED3DERR_INVALIDCALL;
2600 lightInfo->enabledChanged = TRUE;
2601 if(!Enable) {
2602 if(lightInfo->glIndex != -1) {
2603 if(!This->isRecordingState) {
2604 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2607 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2608 lightInfo->glIndex = -1;
2609 } else {
2610 TRACE("Light already disabled, nothing to do\n");
2612 } else {
2613 if (lightInfo->glIndex != -1) {
2614 /* nop */
2615 TRACE("Nothing to do as light was enabled\n");
2616 } else {
2617 int i;
2618 /* Find a free gl light */
2619 for(i = 0; i < This->maxConcurrentLights; i++) {
2620 if(This->stateBlock->activeLights[i] == NULL) {
2621 This->stateBlock->activeLights[i] = lightInfo;
2622 lightInfo->glIndex = i;
2623 break;
2626 if(lightInfo->glIndex == -1) {
2627 ERR("Too many concurrently active lights\n");
2628 return WINED3DERR_INVALIDCALL;
2631 /* i == lightInfo->glIndex */
2632 if(!This->isRecordingState) {
2633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2643 PLIGHTINFOEL *lightInfo = NULL;
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 struct list *e;
2646 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2647 TRACE("(%p) : for idx(%d)\n", This, Index);
2649 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2650 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2651 if(lightInfo->OriginalIndex == Index) break;
2652 lightInfo = NULL;
2655 if (lightInfo == NULL) {
2656 TRACE("Light enabled state requested but light not defined\n");
2657 return WINED3DERR_INVALIDCALL;
2659 /* true is 128 according to SetLightEnable */
2660 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2661 return WINED3D_OK;
2664 /*****
2665 * Get / Set Clip Planes
2666 *****/
2667 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2669 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2671 /* Validate Index */
2672 if (Index >= GL_LIMITS(clipplanes)) {
2673 TRACE("Application has requested clipplane this device doesn't support\n");
2674 return WINED3DERR_INVALIDCALL;
2677 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2679 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2680 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2681 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2682 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2683 TRACE("Application is setting old values over, nothing to do\n");
2684 return WINED3D_OK;
2687 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2688 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2689 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2690 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2692 /* Handle recording of state blocks */
2693 if (This->isRecordingState) {
2694 TRACE("Recording... not performing anything\n");
2695 return WINED3D_OK;
2698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2700 return WINED3D_OK;
2703 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2705 TRACE("(%p) : for idx %d\n", This, Index);
2707 /* Validate Index */
2708 if (Index >= GL_LIMITS(clipplanes)) {
2709 TRACE("Application has requested clipplane this device doesn't support\n");
2710 return WINED3DERR_INVALIDCALL;
2713 pPlane[0] = This->stateBlock->clipplane[Index][0];
2714 pPlane[1] = This->stateBlock->clipplane[Index][1];
2715 pPlane[2] = This->stateBlock->clipplane[Index][2];
2716 pPlane[3] = This->stateBlock->clipplane[Index][3];
2717 return WINED3D_OK;
2720 /*****
2721 * Get / Set Clip Plane Status
2722 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2723 *****/
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2726 FIXME("(%p) : stub\n", This);
2727 if (NULL == pClipStatus) {
2728 return WINED3DERR_INVALIDCALL;
2730 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2731 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2732 return WINED3D_OK;
2735 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2736 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2737 FIXME("(%p) : stub\n", This);
2738 if (NULL == pClipStatus) {
2739 return WINED3DERR_INVALIDCALL;
2741 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2742 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2743 return WINED3D_OK;
2746 /*****
2747 * Get / Set Material
2748 *****/
2749 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2752 This->updateStateBlock->changed.material = TRUE;
2753 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2755 /* Handle recording of state blocks */
2756 if (This->isRecordingState) {
2757 TRACE("Recording... not performing anything\n");
2758 return WINED3D_OK;
2761 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2762 return WINED3D_OK;
2765 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2766 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2767 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2768 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2769 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2770 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2771 pMaterial->Ambient.b, pMaterial->Ambient.a);
2772 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2773 pMaterial->Specular.b, pMaterial->Specular.a);
2774 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2775 pMaterial->Emissive.b, pMaterial->Emissive.a);
2776 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2778 return WINED3D_OK;
2781 /*****
2782 * Get / Set Indices
2783 *****/
2784 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 IWineD3DIndexBuffer *oldIdxs;
2788 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2789 oldIdxs = This->updateStateBlock->pIndexData;
2791 This->updateStateBlock->changed.indices = TRUE;
2792 This->updateStateBlock->pIndexData = pIndexData;
2794 /* Handle recording of state blocks */
2795 if (This->isRecordingState) {
2796 TRACE("Recording... not performing anything\n");
2797 return WINED3D_OK;
2800 if(oldIdxs != pIndexData) {
2801 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2802 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2803 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2805 return WINED3D_OK;
2808 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2809 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2811 *ppIndexData = This->stateBlock->pIndexData;
2813 /* up ref count on ppindexdata */
2814 if (*ppIndexData) {
2815 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2816 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2817 }else{
2818 TRACE("(%p) No index data set\n", This);
2820 TRACE("Returning %p\n", *ppIndexData);
2822 return WINED3D_OK;
2825 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2826 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, UINT BaseIndex) {
2827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2828 TRACE("(%p)->(%d)\n", This, BaseIndex);
2830 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2831 TRACE("Application is setting the old value over, nothing to do\n");
2832 return WINED3D_OK;
2835 This->updateStateBlock->baseVertexIndex = BaseIndex;
2837 if (This->isRecordingState) {
2838 TRACE("Recording... not performing anything\n");
2839 return WINED3D_OK;
2841 /* The base vertex index affects the stream sources */
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2843 return WINED3D_OK;
2846 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, UINT* base_index) {
2847 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2848 TRACE("(%p) : base_index %p\n", This, base_index);
2850 *base_index = This->stateBlock->baseVertexIndex;
2852 TRACE("Returning %u\n", *base_index);
2854 return WINED3D_OK;
2857 /*****
2858 * Get / Set Viewports
2859 *****/
2860 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2863 TRACE("(%p)\n", This);
2864 This->updateStateBlock->changed.viewport = TRUE;
2865 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2867 /* Handle recording of state blocks */
2868 if (This->isRecordingState) {
2869 TRACE("Recording... not performing anything\n");
2870 return WINED3D_OK;
2873 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2874 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2876 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2877 return WINED3D_OK;
2881 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2883 TRACE("(%p)\n", This);
2884 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2885 return WINED3D_OK;
2888 /*****
2889 * Get / Set Render States
2890 * TODO: Verify against dx9 definitions
2891 *****/
2892 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 DWORD oldValue = This->stateBlock->renderState[State];
2897 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2899 This->updateStateBlock->changed.renderState[State] = TRUE;
2900 This->updateStateBlock->renderState[State] = Value;
2902 /* Handle recording of state blocks */
2903 if (This->isRecordingState) {
2904 TRACE("Recording... not performing anything\n");
2905 return WINED3D_OK;
2908 /* Compared here and not before the assignment to allow proper stateblock recording */
2909 if(Value == oldValue) {
2910 TRACE("Application is setting the old value over, nothing to do\n");
2911 } else {
2912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2915 return WINED3D_OK;
2918 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
2921 *pValue = This->stateBlock->renderState[State];
2922 return WINED3D_OK;
2925 /*****
2926 * Get / Set Sampler States
2927 * TODO: Verify against dx9 definitions
2928 *****/
2930 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 DWORD oldValue;
2934 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
2935 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
2937 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2938 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2942 * SetSampler is designed to allow for more than the standard up to 8 textures
2943 * and Geforce has stopped supporting more than 6 standard textures in openGL.
2944 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
2946 * http://developer.nvidia.com/object/General_FAQ.html#t6
2948 * There are two new settings for GForce
2949 * the sampler one:
2950 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
2951 * and the texture one:
2952 * GL_MAX_TEXTURE_COORDS_ARB.
2953 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
2954 ******************/
2956 oldValue = This->stateBlock->samplerState[Sampler][Type];
2957 This->updateStateBlock->samplerState[Sampler][Type] = Value;
2958 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
2960 /* Handle recording of state blocks */
2961 if (This->isRecordingState) {
2962 TRACE("Recording... not performing anything\n");
2963 return WINED3D_OK;
2966 if(oldValue == Value) {
2967 TRACE("Application is setting the old value over, nothing to do\n");
2968 return WINED3D_OK;
2971 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
2973 return WINED3D_OK;
2976 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
2977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
2980 This, Sampler, debug_d3dsamplerstate(Type), Type);
2982 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
2983 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
2986 *Value = This->stateBlock->samplerState[Sampler][Type];
2987 TRACE("(%p) : Returning %#x\n", This, *Value);
2989 return WINED3D_OK;
2992 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
2993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 This->updateStateBlock->changed.scissorRect = TRUE;
2996 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
2997 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
2998 return WINED3D_OK;
3000 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3002 if(This->isRecordingState) {
3003 TRACE("Recording... not performing anything\n");
3004 return WINED3D_OK;
3007 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3009 return WINED3D_OK;
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3015 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3016 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3017 return WINED3D_OK;
3020 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3022 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3024 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3026 This->updateStateBlock->vertexDecl = pDecl;
3027 This->updateStateBlock->changed.vertexDecl = TRUE;
3029 if (This->isRecordingState) {
3030 TRACE("Recording... not performing anything\n");
3031 return WINED3D_OK;
3032 } else if(pDecl == oldDecl) {
3033 /* Checked after the assignment to allow proper stateblock recording */
3034 TRACE("Application is setting the old declaration over, nothing to do\n");
3035 return WINED3D_OK;
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3039 return WINED3D_OK;
3042 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3047 *ppDecl = This->stateBlock->vertexDecl;
3048 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3049 return WINED3D_OK;
3052 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3054 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3056 This->updateStateBlock->vertexShader = pShader;
3057 This->updateStateBlock->changed.vertexShader = TRUE;
3059 if (This->isRecordingState) {
3060 TRACE("Recording... not performing anything\n");
3061 return WINED3D_OK;
3062 } else if(oldShader == pShader) {
3063 /* Checked here to allow proper stateblock recording */
3064 TRACE("App is setting the old shader over, nothing to do\n");
3065 return WINED3D_OK;
3068 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3070 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3072 return WINED3D_OK;
3075 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 if (NULL == ppShader) {
3079 return WINED3DERR_INVALIDCALL;
3081 *ppShader = This->stateBlock->vertexShader;
3082 if( NULL != *ppShader)
3083 IWineD3DVertexShader_AddRef(*ppShader);
3085 TRACE("(%p) : returning %p\n", This, *ppShader);
3086 return WINED3D_OK;
3089 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3090 IWineD3DDevice *iface,
3091 UINT start,
3092 CONST BOOL *srcData,
3093 UINT count) {
3095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3096 int i, cnt = min(count, MAX_CONST_B - start);
3098 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3099 iface, srcData, start, count);
3101 if (srcData == NULL || cnt < 0)
3102 return WINED3DERR_INVALIDCALL;
3104 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3105 for (i = 0; i < cnt; i++)
3106 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3108 for (i = start; i < cnt + start; ++i) {
3109 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3112 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3114 return WINED3D_OK;
3117 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3118 IWineD3DDevice *iface,
3119 UINT start,
3120 BOOL *dstData,
3121 UINT count) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 int cnt = min(count, MAX_CONST_B - start);
3126 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3127 iface, dstData, start, count);
3129 if (dstData == NULL || cnt < 0)
3130 return WINED3DERR_INVALIDCALL;
3132 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3137 IWineD3DDevice *iface,
3138 UINT start,
3139 CONST int *srcData,
3140 UINT count) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3143 int i, cnt = min(count, MAX_CONST_I - start);
3145 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3146 iface, srcData, start, count);
3148 if (srcData == NULL || cnt < 0)
3149 return WINED3DERR_INVALIDCALL;
3151 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3152 for (i = 0; i < cnt; i++)
3153 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3154 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3156 for (i = start; i < cnt + start; ++i) {
3157 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3160 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3162 return WINED3D_OK;
3165 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3166 IWineD3DDevice *iface,
3167 UINT start,
3168 int *dstData,
3169 UINT count) {
3171 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3172 int cnt = min(count, MAX_CONST_I - start);
3174 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3175 iface, dstData, start, count);
3177 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3178 return WINED3DERR_INVALIDCALL;
3180 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3181 return WINED3D_OK;
3184 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3185 IWineD3DDevice *iface,
3186 UINT start,
3187 CONST float *srcData,
3188 UINT count) {
3190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3191 int i;
3193 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3194 iface, srcData, start, count);
3196 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3197 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3198 return WINED3DERR_INVALIDCALL;
3200 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3201 if(TRACE_ON(d3d)) {
3202 for (i = 0; i < count; i++)
3203 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3204 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3207 for (i = start; i < count + start; ++i) {
3208 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3209 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3210 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3211 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3212 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3214 ptr->idx[ptr->count++] = i;
3215 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3221 return WINED3D_OK;
3224 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3225 IWineD3DDevice *iface,
3226 UINT start,
3227 float *dstData,
3228 UINT count) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3233 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3234 iface, dstData, start, count);
3236 if (dstData == NULL || cnt < 0)
3237 return WINED3DERR_INVALIDCALL;
3239 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3240 return WINED3D_OK;
3243 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3244 DWORD i;
3245 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3250 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3251 int i = This->rev_tex_unit_map[unit];
3252 int j = This->texUnitMap[stage];
3254 This->texUnitMap[stage] = unit;
3255 if (i != -1 && i != stage) {
3256 This->texUnitMap[i] = -1;
3259 This->rev_tex_unit_map[unit] = stage;
3260 if (j != -1 && j != unit) {
3261 This->rev_tex_unit_map[j] = -1;
3265 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3266 int i;
3268 for (i = 0; i < MAX_TEXTURES; ++i) {
3269 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3270 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3271 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3272 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3273 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3274 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3275 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3276 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3278 if (color_op == WINED3DTOP_DISABLE) {
3279 /* Not used, and disable higher stages */
3280 while (i < MAX_TEXTURES) {
3281 This->fixed_function_usage_map[i] = FALSE;
3282 ++i;
3284 break;
3287 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3288 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3289 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3290 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3291 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3292 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3293 This->fixed_function_usage_map[i] = TRUE;
3294 } else {
3295 This->fixed_function_usage_map[i] = FALSE;
3298 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3299 This->fixed_function_usage_map[i+1] = TRUE;
3304 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3305 int i, tex;
3307 device_update_fixed_function_usage_map(This);
3309 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3310 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3311 if (!This->fixed_function_usage_map[i]) continue;
3313 if (This->texUnitMap[i] != i) {
3314 device_map_stage(This, i, i);
3315 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3316 markTextureStagesDirty(This, i);
3319 return;
3322 /* Now work out the mapping */
3323 tex = 0;
3324 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3325 if (!This->fixed_function_usage_map[i]) continue;
3327 if (This->texUnitMap[i] != tex) {
3328 device_map_stage(This, i, tex);
3329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3330 markTextureStagesDirty(This, i);
3333 ++tex;
3337 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3338 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3339 int i;
3341 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3342 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3343 device_map_stage(This, i, i);
3344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3345 if (i < MAX_TEXTURES) {
3346 markTextureStagesDirty(This, i);
3352 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3353 int current_mapping = This->rev_tex_unit_map[unit];
3355 if (current_mapping == -1) {
3356 /* Not currently used */
3357 return TRUE;
3360 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3361 /* Used by a fragment sampler */
3363 if (!pshader_sampler_tokens) {
3364 /* No pixel shader, check fixed function */
3365 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3368 /* Pixel shader, check the shader's sampler map */
3369 return !pshader_sampler_tokens[current_mapping];
3372 /* Used by a vertex sampler */
3373 return !vshader_sampler_tokens[current_mapping];
3376 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3377 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3378 DWORD *pshader_sampler_tokens = NULL;
3379 int start = GL_LIMITS(combined_samplers) - 1;
3380 int i;
3382 if (ps) {
3383 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3385 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3386 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3387 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3390 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3391 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3392 if (vshader_sampler_tokens[i]) {
3393 if (This->texUnitMap[vsampler_idx] != -1) {
3394 /* Already mapped somewhere */
3395 continue;
3398 while (start >= 0) {
3399 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3400 device_map_stage(This, vsampler_idx, start);
3401 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3403 --start;
3404 break;
3407 --start;
3413 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3414 BOOL vs = use_vs(This);
3415 BOOL ps = use_ps(This);
3417 * Rules are:
3418 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3419 * that would be really messy and require shader recompilation
3420 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3421 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3423 if (ps) {
3424 device_map_psamplers(This);
3425 } else {
3426 device_map_fixed_function_samplers(This);
3429 if (vs) {
3430 device_map_vsamplers(This, ps);
3434 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3436 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3437 This->updateStateBlock->pixelShader = pShader;
3438 This->updateStateBlock->changed.pixelShader = TRUE;
3440 /* Handle recording of state blocks */
3441 if (This->isRecordingState) {
3442 TRACE("Recording... not performing anything\n");
3445 if (This->isRecordingState) {
3446 TRACE("Recording... not performing anything\n");
3447 return WINED3D_OK;
3450 if(pShader == oldShader) {
3451 TRACE("App is setting the old pixel shader over, nothing to do\n");
3452 return WINED3D_OK;
3455 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3456 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3458 return WINED3D_OK;
3461 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3464 if (NULL == ppShader) {
3465 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3466 return WINED3DERR_INVALIDCALL;
3469 *ppShader = This->stateBlock->pixelShader;
3470 if (NULL != *ppShader) {
3471 IWineD3DPixelShader_AddRef(*ppShader);
3473 TRACE("(%p) : returning %p\n", This, *ppShader);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3478 IWineD3DDevice *iface,
3479 UINT start,
3480 CONST BOOL *srcData,
3481 UINT count) {
3483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3484 int i, cnt = min(count, MAX_CONST_B - start);
3486 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3487 iface, srcData, start, count);
3489 if (srcData == NULL || cnt < 0)
3490 return WINED3DERR_INVALIDCALL;
3492 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3493 for (i = 0; i < cnt; i++)
3494 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3496 for (i = start; i < cnt + start; ++i) {
3497 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3500 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3502 return WINED3D_OK;
3505 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3506 IWineD3DDevice *iface,
3507 UINT start,
3508 BOOL *dstData,
3509 UINT count) {
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3512 int cnt = min(count, MAX_CONST_B - start);
3514 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3515 iface, dstData, start, count);
3517 if (dstData == NULL || cnt < 0)
3518 return WINED3DERR_INVALIDCALL;
3520 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3521 return WINED3D_OK;
3524 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3525 IWineD3DDevice *iface,
3526 UINT start,
3527 CONST int *srcData,
3528 UINT count) {
3530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3531 int i, cnt = min(count, MAX_CONST_I - start);
3533 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3534 iface, srcData, start, count);
3536 if (srcData == NULL || cnt < 0)
3537 return WINED3DERR_INVALIDCALL;
3539 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3540 for (i = 0; i < cnt; i++)
3541 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3542 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3544 for (i = start; i < cnt + start; ++i) {
3545 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3548 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3550 return WINED3D_OK;
3553 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3554 IWineD3DDevice *iface,
3555 UINT start,
3556 int *dstData,
3557 UINT count) {
3559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3560 int cnt = min(count, MAX_CONST_I - start);
3562 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3563 iface, dstData, start, count);
3565 if (dstData == NULL || cnt < 0)
3566 return WINED3DERR_INVALIDCALL;
3568 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3569 return WINED3D_OK;
3572 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3573 IWineD3DDevice *iface,
3574 UINT start,
3575 CONST float *srcData,
3576 UINT count) {
3578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3579 int i;
3581 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3582 iface, srcData, start, count);
3584 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3585 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3586 return WINED3DERR_INVALIDCALL;
3588 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3589 if(TRACE_ON(d3d)) {
3590 for (i = 0; i < count; i++)
3591 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3592 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3595 for (i = start; i < count + start; ++i) {
3596 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3597 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3598 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3599 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3600 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3602 ptr->idx[ptr->count++] = i;
3603 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3609 return WINED3D_OK;
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3613 IWineD3DDevice *iface,
3614 UINT start,
3615 float *dstData,
3616 UINT count) {
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3628 return WINED3D_OK;
3631 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3632 static HRESULT
3633 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3634 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3635 unsigned int i;
3636 DWORD DestFVF = dest->fvf;
3637 WINED3DVIEWPORT vp;
3638 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3639 BOOL doClip;
3640 int numTextures;
3642 if (lpStrideData->u.s.normal.lpData) {
3643 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3646 if (lpStrideData->u.s.position.lpData == NULL) {
3647 ERR("Source has no position mask\n");
3648 return WINED3DERR_INVALIDCALL;
3651 /* We might access VBOs from this code, so hold the lock */
3652 ENTER_GL();
3654 if (dest->resource.allocatedMemory == NULL) {
3655 /* This may happen if we do direct locking into a vbo. Unlikely,
3656 * but theoretically possible(ddraw processvertices test)
3658 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3659 if(!dest->resource.allocatedMemory) {
3660 LEAVE_GL();
3661 ERR("Out of memory\n");
3662 return E_OUTOFMEMORY;
3664 if(dest->vbo) {
3665 void *src;
3666 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3667 checkGLcall("glBindBufferARB");
3668 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3669 if(src) {
3670 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3672 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3673 checkGLcall("glUnmapBufferARB");
3677 /* Get a pointer into the destination vbo(create one if none exists) and
3678 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3680 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3681 CreateVBO(dest);
3684 if(dest->vbo) {
3685 unsigned char extrabytes = 0;
3686 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3687 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3688 * this may write 4 extra bytes beyond the area that should be written
3690 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3691 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3692 if(!dest_conv_addr) {
3693 ERR("Out of memory\n");
3694 /* Continue without storing converted vertices */
3696 dest_conv = dest_conv_addr;
3699 /* Should I clip?
3700 * a) WINED3DRS_CLIPPING is enabled
3701 * b) WINED3DVOP_CLIP is passed
3703 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3704 static BOOL warned = FALSE;
3706 * The clipping code is not quite correct. Some things need
3707 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3708 * so disable clipping for now.
3709 * (The graphics in Half-Life are broken, and my processvertices
3710 * test crashes with IDirect3DDevice3)
3711 doClip = TRUE;
3713 doClip = FALSE;
3714 if(!warned) {
3715 warned = TRUE;
3716 FIXME("Clipping is broken and disabled for now\n");
3718 } else doClip = FALSE;
3719 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3721 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3722 WINED3DTS_VIEW,
3723 &view_mat);
3724 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3725 WINED3DTS_PROJECTION,
3726 &proj_mat);
3727 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3728 WINED3DTS_WORLDMATRIX(0),
3729 &world_mat);
3731 TRACE("View mat:\n");
3732 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);
3733 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);
3734 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);
3735 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);
3737 TRACE("Proj mat:\n");
3738 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);
3739 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);
3740 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);
3741 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);
3743 TRACE("World mat:\n");
3744 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);
3745 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);
3746 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);
3747 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);
3749 /* Get the viewport */
3750 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3751 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3752 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3754 multiply_matrix(&mat,&view_mat,&world_mat);
3755 multiply_matrix(&mat,&proj_mat,&mat);
3757 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3759 for (i = 0; i < dwCount; i+= 1) {
3760 unsigned int tex_index;
3762 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3763 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3764 /* The position first */
3765 float *p =
3766 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3767 float x, y, z, rhw;
3768 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3770 /* Multiplication with world, view and projection matrix */
3771 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);
3772 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);
3773 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);
3774 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);
3776 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3778 /* WARNING: The following things are taken from d3d7 and were not yet checked
3779 * against d3d8 or d3d9!
3782 /* Clipping conditions: From
3783 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3785 * A vertex is clipped if it does not match the following requirements
3786 * -rhw < x <= rhw
3787 * -rhw < y <= rhw
3788 * 0 < z <= rhw
3789 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3791 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3792 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3796 if( !doClip ||
3797 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3798 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3799 ( rhw > eps ) ) ) {
3801 /* "Normal" viewport transformation (not clipped)
3802 * 1) The values are divided by rhw
3803 * 2) The y axis is negative, so multiply it with -1
3804 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3805 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3806 * 4) Multiply x with Width/2 and add Width/2
3807 * 5) The same for the height
3808 * 6) Add the viewpoint X and Y to the 2D coordinates and
3809 * The minimum Z value to z
3810 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3812 * Well, basically it's simply a linear transformation into viewport
3813 * coordinates
3816 x /= rhw;
3817 y /= rhw;
3818 z /= rhw;
3820 y *= -1;
3822 x *= vp.Width / 2;
3823 y *= vp.Height / 2;
3824 z *= vp.MaxZ - vp.MinZ;
3826 x += vp.Width / 2 + vp.X;
3827 y += vp.Height / 2 + vp.Y;
3828 z += vp.MinZ;
3830 rhw = 1 / rhw;
3831 } else {
3832 /* That vertex got clipped
3833 * Contrary to OpenGL it is not dropped completely, it just
3834 * undergoes a different calculation.
3836 TRACE("Vertex got clipped\n");
3837 x += rhw;
3838 y += rhw;
3840 x /= 2;
3841 y /= 2;
3843 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3844 * outside of the main vertex buffer memory. That needs some more
3845 * investigation...
3849 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3852 ( (float *) dest_ptr)[0] = x;
3853 ( (float *) dest_ptr)[1] = y;
3854 ( (float *) dest_ptr)[2] = z;
3855 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3857 dest_ptr += 3 * sizeof(float);
3859 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3860 dest_ptr += sizeof(float);
3863 if(dest_conv) {
3864 float w = 1 / rhw;
3865 ( (float *) dest_conv)[0] = x * w;
3866 ( (float *) dest_conv)[1] = y * w;
3867 ( (float *) dest_conv)[2] = z * w;
3868 ( (float *) dest_conv)[3] = w;
3870 dest_conv += 3 * sizeof(float);
3872 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3873 dest_conv += sizeof(float);
3877 if (DestFVF & WINED3DFVF_PSIZE) {
3878 dest_ptr += sizeof(DWORD);
3879 if(dest_conv) dest_conv += sizeof(DWORD);
3881 if (DestFVF & WINED3DFVF_NORMAL) {
3882 float *normal =
3883 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3884 /* AFAIK this should go into the lighting information */
3885 FIXME("Didn't expect the destination to have a normal\n");
3886 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3887 if(dest_conv) {
3888 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3892 if (DestFVF & WINED3DFVF_DIFFUSE) {
3893 DWORD *color_d =
3894 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3895 if(!color_d) {
3896 static BOOL warned = FALSE;
3898 if(!warned) {
3899 ERR("No diffuse color in source, but destination has one\n");
3900 warned = TRUE;
3903 *( (DWORD *) dest_ptr) = 0xffffffff;
3904 dest_ptr += sizeof(DWORD);
3906 if(dest_conv) {
3907 *( (DWORD *) dest_conv) = 0xffffffff;
3908 dest_conv += sizeof(DWORD);
3911 else {
3912 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
3913 if(dest_conv) {
3914 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
3915 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
3916 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
3917 dest_conv += sizeof(DWORD);
3922 if (DestFVF & WINED3DFVF_SPECULAR) {
3923 /* What's the color value in the feedback buffer? */
3924 DWORD *color_s =
3925 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
3926 if(!color_s) {
3927 static BOOL warned = FALSE;
3929 if(!warned) {
3930 ERR("No specular color in source, but destination has one\n");
3931 warned = TRUE;
3934 *( (DWORD *) dest_ptr) = 0xFF000000;
3935 dest_ptr += sizeof(DWORD);
3937 if(dest_conv) {
3938 *( (DWORD *) dest_conv) = 0xFF000000;
3939 dest_conv += sizeof(DWORD);
3942 else {
3943 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
3944 if(dest_conv) {
3945 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
3946 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
3947 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
3948 dest_conv += sizeof(DWORD);
3953 for (tex_index = 0; tex_index < numTextures; tex_index++) {
3954 float *tex_coord =
3955 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
3956 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
3957 if(!tex_coord) {
3958 ERR("No source texture, but destination requests one\n");
3959 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3960 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
3962 else {
3963 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3964 if(dest_conv) {
3965 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
3971 if(dest_conv) {
3972 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3973 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
3974 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
3975 dwCount * get_flexible_vertex_size(DestFVF),
3976 dest_conv_addr));
3977 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
3978 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
3981 LEAVE_GL();
3983 return WINED3D_OK;
3985 #undef copy_and_next
3987 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
3988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3989 WineDirect3DVertexStridedData strided;
3990 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
3991 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
3993 if(pVertexDecl) {
3994 ERR("Output vertex declaration not implemented yet\n");
3997 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
3998 * and this call is quite performance critical, so don't call needlessly
4000 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4001 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4004 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4005 * control the streamIsUP flag, thus restore it afterwards.
4007 This->stateBlock->streamIsUP = FALSE;
4008 memset(&strided, 0, sizeof(strided));
4009 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4010 This->stateBlock->streamIsUP = streamWasUP;
4012 if(vbo || SrcStartIndex) {
4013 unsigned int i;
4014 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4015 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4017 * Also get the start index in, but only loop over all elements if there's something to add at all.
4019 #define FIXSRC(type) \
4020 if(strided.u.s.type.VBO) { \
4021 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4022 strided.u.s.type.VBO = 0; \
4023 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4024 ENTER_GL(); \
4025 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4026 vb->vbo = 0; \
4027 LEAVE_GL(); \
4029 if(strided.u.s.type.lpData) { \
4030 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4032 FIXSRC(position);
4033 FIXSRC(blendWeights);
4034 FIXSRC(blendMatrixIndices);
4035 FIXSRC(normal);
4036 FIXSRC(pSize);
4037 FIXSRC(diffuse);
4038 FIXSRC(specular);
4039 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4040 FIXSRC(texCoords[i]);
4042 FIXSRC(position2);
4043 FIXSRC(normal2);
4044 FIXSRC(tangent);
4045 FIXSRC(binormal);
4046 FIXSRC(tessFactor);
4047 FIXSRC(fog);
4048 FIXSRC(depth);
4049 FIXSRC(sample);
4050 #undef FIXSRC
4053 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4056 /*****
4057 * Get / Set Texture Stage States
4058 * TODO: Verify against dx9 definitions
4059 *****/
4060 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4062 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4064 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4066 if (Stage >= MAX_TEXTURES) {
4067 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4068 return WINED3D_OK;
4071 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4072 This->updateStateBlock->textureState[Stage][Type] = Value;
4074 if (This->isRecordingState) {
4075 TRACE("Recording... not performing anything\n");
4076 return WINED3D_OK;
4079 /* Checked after the assignments to allow proper stateblock recording */
4080 if(oldValue == Value) {
4081 TRACE("App is setting the old value over, nothing to do\n");
4082 return WINED3D_OK;
4085 if(Stage > This->stateBlock->lowest_disabled_stage &&
4086 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4087 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4088 * Changes in other states are important on disabled stages too
4090 return WINED3D_OK;
4093 if(Type == WINED3DTSS_COLOROP) {
4094 int i;
4096 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4097 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4098 * they have to be disabled
4100 * The current stage is dirtified below.
4102 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4103 TRACE("Additionally dirtifying stage %d\n", i);
4104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4106 This->stateBlock->lowest_disabled_stage = Stage;
4107 TRACE("New lowest disabled: %d\n", Stage);
4108 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4109 /* Previously disabled stage enabled. Stages above it may need enabling
4110 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4111 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4113 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4116 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4117 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4118 break;
4120 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4123 This->stateBlock->lowest_disabled_stage = i;
4124 TRACE("New lowest disabled: %d\n", i);
4126 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4127 /* TODO: Built a stage -> texture unit mapping for register combiners */
4131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4133 return WINED3D_OK;
4136 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4138 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4139 *pValue = This->updateStateBlock->textureState[Stage][Type];
4140 return WINED3D_OK;
4143 /*****
4144 * Get / Set Texture
4145 *****/
4146 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4148 IWineD3DBaseTexture *oldTexture;
4150 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4152 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4153 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4156 oldTexture = This->updateStateBlock->textures[Stage];
4158 if(pTexture != NULL) {
4159 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4161 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4162 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4163 return WINED3DERR_INVALIDCALL;
4165 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4168 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4169 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4171 This->updateStateBlock->changed.textures[Stage] = TRUE;
4172 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4173 This->updateStateBlock->textures[Stage] = pTexture;
4175 /* Handle recording of state blocks */
4176 if (This->isRecordingState) {
4177 TRACE("Recording... not performing anything\n");
4178 return WINED3D_OK;
4181 if(oldTexture == pTexture) {
4182 TRACE("App is setting the same texture again, nothing to do\n");
4183 return WINED3D_OK;
4186 /** NOTE: MSDN says that setTexture increases the reference count,
4187 * and the the application must set the texture back to null (or have a leaky application),
4188 * This means we should pass the refcount up to the parent
4189 *******************************/
4190 if (NULL != This->updateStateBlock->textures[Stage]) {
4191 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4192 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4194 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4195 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4196 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4197 * so the COLOROP and ALPHAOP have to be dirtified.
4199 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4202 if(bindCount == 1) {
4203 new->baseTexture.sampler = Stage;
4205 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4209 if (NULL != oldTexture) {
4210 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4211 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4213 IWineD3DBaseTexture_Release(oldTexture);
4214 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4219 if(bindCount && old->baseTexture.sampler == Stage) {
4220 int i;
4221 /* Have to do a search for the other sampler(s) where the texture is bound to
4222 * Shouldn't happen as long as apps bind a texture only to one stage
4224 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4225 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4226 if(This->updateStateBlock->textures[i] == oldTexture) {
4227 old->baseTexture.sampler = i;
4228 break;
4234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4236 return WINED3D_OK;
4239 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4242 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4244 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4245 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4248 *ppTexture=This->stateBlock->textures[Stage];
4249 if (*ppTexture)
4250 IWineD3DBaseTexture_AddRef(*ppTexture);
4252 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4254 return WINED3D_OK;
4257 /*****
4258 * Get Back Buffer
4259 *****/
4260 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4261 IWineD3DSurface **ppBackBuffer) {
4262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4263 IWineD3DSwapChain *swapChain;
4264 HRESULT hr;
4266 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4268 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4269 if (hr == WINED3D_OK) {
4270 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4271 IWineD3DSwapChain_Release(swapChain);
4272 } else {
4273 *ppBackBuffer = NULL;
4275 return hr;
4278 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4280 WARN("(%p) : stub, calling idirect3d for now\n", This);
4281 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4284 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4286 IWineD3DSwapChain *swapChain;
4287 HRESULT hr;
4289 if(iSwapChain > 0) {
4290 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4291 if (hr == WINED3D_OK) {
4292 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4293 IWineD3DSwapChain_Release(swapChain);
4294 } else {
4295 FIXME("(%p) Error getting display mode\n", This);
4297 } else {
4298 /* Don't read the real display mode,
4299 but return the stored mode instead. X11 can't change the color
4300 depth, and some apps are pretty angry if they SetDisplayMode from
4301 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4303 Also don't relay to the swapchain because with ddraw it's possible
4304 that there isn't a swapchain at all */
4305 pMode->Width = This->ddraw_width;
4306 pMode->Height = This->ddraw_height;
4307 pMode->Format = This->ddraw_format;
4308 pMode->RefreshRate = 0;
4309 hr = WINED3D_OK;
4312 return hr;
4315 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4317 TRACE("(%p)->(%p)\n", This, hWnd);
4319 if(This->ddraw_fullscreen) {
4320 if(This->ddraw_window && This->ddraw_window != hWnd) {
4321 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4323 if(hWnd && This->ddraw_window != hWnd) {
4324 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4328 This->ddraw_window = hWnd;
4329 return WINED3D_OK;
4332 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4334 TRACE("(%p)->(%p)\n", This, hWnd);
4336 *hWnd = This->ddraw_window;
4337 return WINED3D_OK;
4340 /*****
4341 * Stateblock related functions
4342 *****/
4344 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4346 IWineD3DStateBlockImpl *object;
4347 HRESULT temp_result;
4348 int i;
4350 TRACE("(%p)\n", This);
4352 if (This->isRecordingState) {
4353 return WINED3DERR_INVALIDCALL;
4356 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4357 if (NULL == object ) {
4358 FIXME("(%p)Error allocating memory for stateblock\n", This);
4359 return E_OUTOFMEMORY;
4361 TRACE("(%p) created object %p\n", This, object);
4362 object->wineD3DDevice= This;
4363 /** FIXME: object->parent = parent; **/
4364 object->parent = NULL;
4365 object->blockType = WINED3DSBT_RECORDED;
4366 object->ref = 1;
4367 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4369 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4370 list_init(&object->lightMap[i]);
4373 temp_result = allocate_shader_constants(object);
4374 if (WINED3D_OK != temp_result)
4375 return temp_result;
4377 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4378 This->updateStateBlock = object;
4379 This->isRecordingState = TRUE;
4381 TRACE("(%p) recording stateblock %p\n",This , object);
4382 return WINED3D_OK;
4385 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4387 unsigned int i, j;
4388 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4390 if (!This->isRecordingState) {
4391 FIXME("(%p) not recording! returning error\n", This);
4392 *ppStateBlock = NULL;
4393 return WINED3DERR_INVALIDCALL;
4396 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4397 if(object->changed.renderState[i]) {
4398 object->contained_render_states[object->num_contained_render_states] = i;
4399 object->num_contained_render_states++;
4402 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4403 if(object->changed.transform[i]) {
4404 object->contained_transform_states[object->num_contained_transform_states] = i;
4405 object->num_contained_transform_states++;
4408 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4409 if(object->changed.vertexShaderConstantsF[i]) {
4410 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4411 object->num_contained_vs_consts_f++;
4414 for(i = 0; i < MAX_CONST_I; i++) {
4415 if(object->changed.vertexShaderConstantsI[i]) {
4416 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4417 object->num_contained_vs_consts_i++;
4420 for(i = 0; i < MAX_CONST_B; i++) {
4421 if(object->changed.vertexShaderConstantsB[i]) {
4422 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4423 object->num_contained_vs_consts_b++;
4426 for(i = 0; i < MAX_CONST_I; i++) {
4427 if(object->changed.pixelShaderConstantsI[i]) {
4428 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4429 object->num_contained_ps_consts_i++;
4432 for(i = 0; i < MAX_CONST_B; i++) {
4433 if(object->changed.pixelShaderConstantsB[i]) {
4434 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4435 object->num_contained_ps_consts_b++;
4438 for(i = 0; i < MAX_TEXTURES; i++) {
4439 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4440 if(object->changed.textureState[i][j]) {
4441 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4442 object->contained_tss_states[object->num_contained_tss_states].state = j;
4443 object->num_contained_tss_states++;
4447 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4448 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4449 if(object->changed.samplerState[i][j]) {
4450 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4451 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4452 object->num_contained_sampler_states++;
4457 *ppStateBlock = (IWineD3DStateBlock*) object;
4458 This->isRecordingState = FALSE;
4459 This->updateStateBlock = This->stateBlock;
4460 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4461 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4462 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4463 return WINED3D_OK;
4466 /*****
4467 * Scene related functions
4468 *****/
4469 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4470 /* At the moment we have no need for any functionality at the beginning
4471 of a scene */
4472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4473 TRACE("(%p)\n", This);
4475 if(This->inScene) {
4476 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4477 return WINED3DERR_INVALIDCALL;
4479 This->inScene = TRUE;
4480 return WINED3D_OK;
4483 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 TRACE("(%p)\n", This);
4487 if(!This->inScene) {
4488 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4489 return WINED3DERR_INVALIDCALL;
4492 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4493 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4495 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4496 ENTER_GL();
4497 glFlush();
4498 checkGLcall("glFlush");
4499 LEAVE_GL();
4501 This->inScene = FALSE;
4502 return WINED3D_OK;
4505 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4506 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4507 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4509 IWineD3DSwapChain *swapChain = NULL;
4510 int i;
4511 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4513 TRACE("(%p) Presenting the frame\n", This);
4515 for(i = 0 ; i < swapchains ; i ++) {
4517 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4518 TRACE("presentinng chain %d, %p\n", i, swapChain);
4519 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4520 IWineD3DSwapChain_Release(swapChain);
4523 return WINED3D_OK;
4526 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4527 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4529 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4531 GLbitfield glMask = 0;
4532 unsigned int i;
4533 CONST WINED3DRECT* curRect;
4535 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4536 Count, pRects, Flags, Color, Z, Stencil);
4538 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4539 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4540 /* TODO: What about depth stencil buffers without stencil bits? */
4541 return WINED3DERR_INVALIDCALL;
4544 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4545 * and not the last active one.
4547 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4548 ENTER_GL();
4550 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4551 apply_fbo_state(iface);
4554 if (Count > 0 && pRects) {
4555 curRect = pRects;
4556 } else {
4557 curRect = NULL;
4560 /* Only set the values up once, as they are not changing */
4561 if (Flags & WINED3DCLEAR_STENCIL) {
4562 glClearStencil(Stencil);
4563 checkGLcall("glClearStencil");
4564 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4565 glStencilMask(0xFFFFFFFF);
4568 if (Flags & WINED3DCLEAR_ZBUFFER) {
4569 glDepthMask(GL_TRUE);
4570 glClearDepth(Z);
4571 checkGLcall("glClearDepth");
4572 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4576 if (Flags & WINED3DCLEAR_TARGET) {
4577 TRACE("Clearing screen with glClear to color %x\n", Color);
4578 glClearColor(D3DCOLOR_R(Color),
4579 D3DCOLOR_G(Color),
4580 D3DCOLOR_B(Color),
4581 D3DCOLOR_A(Color));
4582 checkGLcall("glClearColor");
4584 /* Clear ALL colors! */
4585 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4586 glMask = glMask | GL_COLOR_BUFFER_BIT;
4589 if (!curRect) {
4590 /* In drawable flag is set below */
4592 if (This->render_offscreen) {
4593 glScissor(This->stateBlock->viewport.X,
4594 This->stateBlock->viewport.Y,
4595 This->stateBlock->viewport.Width,
4596 This->stateBlock->viewport.Height);
4597 } else {
4598 glScissor(This->stateBlock->viewport.X,
4599 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4600 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4601 This->stateBlock->viewport.Width,
4602 This->stateBlock->viewport.Height);
4604 checkGLcall("glScissor");
4605 glClear(glMask);
4606 checkGLcall("glClear");
4607 } else {
4608 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4609 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4611 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4612 curRect[0].x2 < target->currentDesc.Width ||
4613 curRect[0].y2 < target->currentDesc.Height) {
4614 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4615 blt_to_drawable(This, target);
4619 /* Now process each rect in turn */
4620 for (i = 0; i < Count; i++) {
4621 /* Note gl uses lower left, width/height */
4622 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4623 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4624 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4625 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4627 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4628 * The rectangle is not cleared, no error is returned, but further rectanlges are
4629 * still cleared if they are valid
4631 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4632 TRACE("Rectangle with negative dimensions, ignoring\n");
4633 continue;
4636 if(This->render_offscreen) {
4637 glScissor(curRect[i].x1, curRect[i].y1,
4638 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4639 } else {
4640 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4641 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4643 checkGLcall("glScissor");
4645 glClear(glMask);
4646 checkGLcall("glClear");
4650 /* Restore the old values (why..?) */
4651 if (Flags & WINED3DCLEAR_STENCIL) {
4652 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4654 if (Flags & WINED3DCLEAR_TARGET) {
4655 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4656 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4657 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4658 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4659 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4662 LEAVE_GL();
4664 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4665 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4667 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4668 target->Flags |= SFLAG_INTEXTURE;
4669 target->Flags &= ~SFLAG_INSYSMEM;
4670 } else {
4671 target->Flags |= SFLAG_INDRAWABLE;
4672 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4674 return WINED3D_OK;
4677 /*****
4678 * Drawing functions
4679 *****/
4680 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4681 UINT PrimitiveCount) {
4683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4685 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4686 debug_d3dprimitivetype(PrimitiveType),
4687 StartVertex, PrimitiveCount);
4689 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4690 if(This->stateBlock->streamIsUP) {
4691 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4692 This->stateBlock->streamIsUP = FALSE;
4695 if(This->stateBlock->loadBaseVertexIndex != 0) {
4696 This->stateBlock->loadBaseVertexIndex = 0;
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4699 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4700 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4701 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4702 return WINED3D_OK;
4705 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4706 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4707 WINED3DPRIMITIVETYPE PrimitiveType,
4708 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4711 UINT idxStride = 2;
4712 IWineD3DIndexBuffer *pIB;
4713 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4714 GLuint vbo;
4716 pIB = This->stateBlock->pIndexData;
4717 if (!pIB) {
4718 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4719 * without an index buffer set. (The first time at least...)
4720 * D3D8 simply dies, but I doubt it can do much harm to return
4721 * D3DERR_INVALIDCALL there as well. */
4722 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4723 return WINED3DERR_INVALIDCALL;
4726 if(This->stateBlock->streamIsUP) {
4727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4728 This->stateBlock->streamIsUP = FALSE;
4730 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4732 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4733 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4734 minIndex, NumVertices, startIndex, primCount);
4736 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4737 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4738 idxStride = 2;
4739 } else {
4740 idxStride = 4;
4743 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4744 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4745 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4748 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4749 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4751 return WINED3D_OK;
4754 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4755 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4756 UINT VertexStreamZeroStride) {
4757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4758 IWineD3DVertexBuffer *vb;
4760 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4761 debug_d3dprimitivetype(PrimitiveType),
4762 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4764 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4765 vb = This->stateBlock->streamSource[0];
4766 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4767 if(vb) IWineD3DVertexBuffer_Release(vb);
4768 This->stateBlock->streamOffset[0] = 0;
4769 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4770 This->stateBlock->streamIsUP = TRUE;
4771 This->stateBlock->loadBaseVertexIndex = 0;
4773 /* TODO: Only mark dirty if drawing from a different UP address */
4774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4776 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4777 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4779 /* MSDN specifies stream zero settings must be set to NULL */
4780 This->stateBlock->streamStride[0] = 0;
4781 This->stateBlock->streamSource[0] = NULL;
4783 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4784 * the new stream sources or use UP drawing again
4786 return WINED3D_OK;
4789 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4790 UINT MinVertexIndex, UINT NumVertices,
4791 UINT PrimitiveCount, CONST void* pIndexData,
4792 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4793 UINT VertexStreamZeroStride) {
4794 int idxStride;
4795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4796 IWineD3DVertexBuffer *vb;
4797 IWineD3DIndexBuffer *ib;
4799 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4800 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4801 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4802 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4804 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4805 idxStride = 2;
4806 } else {
4807 idxStride = 4;
4810 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4811 vb = This->stateBlock->streamSource[0];
4812 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4813 if(vb) IWineD3DVertexBuffer_Release(vb);
4814 This->stateBlock->streamIsUP = TRUE;
4815 This->stateBlock->streamOffset[0] = 0;
4816 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4818 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4819 This->stateBlock->baseVertexIndex = 0;
4820 This->stateBlock->loadBaseVertexIndex = 0;
4821 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4823 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4825 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4827 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4828 This->stateBlock->streamSource[0] = NULL;
4829 This->stateBlock->streamStride[0] = 0;
4830 ib = This->stateBlock->pIndexData;
4831 if(ib) {
4832 IWineD3DIndexBuffer_Release(ib);
4833 This->stateBlock->pIndexData = NULL;
4835 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4836 * SetStreamSource to specify a vertex buffer
4839 return WINED3D_OK;
4842 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4843 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4845 /* Mark the state dirty until we have nicer tracking
4846 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4847 * that value.
4849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4850 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4851 This->stateBlock->baseVertexIndex = 0;
4852 This->up_strided = DrawPrimStrideData;
4853 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4854 This->up_strided = NULL;
4855 return WINED3D_OK;
4858 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4860 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4862 /* Mark the state dirty until we have nicer tracking
4863 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4864 * that value.
4866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4868 This->stateBlock->streamIsUP = TRUE;
4869 This->stateBlock->baseVertexIndex = 0;
4870 This->up_strided = DrawPrimStrideData;
4871 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4872 This->up_strided = NULL;
4873 return WINED3D_OK;
4877 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4878 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4880 HRESULT hr = WINED3D_OK;
4881 WINED3DRESOURCETYPE sourceType;
4882 WINED3DRESOURCETYPE destinationType;
4883 int i ,levels;
4885 /* TODO: think about moving the code into IWineD3DBaseTexture */
4887 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4889 /* verify that the source and destination textures aren't NULL */
4890 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4891 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4892 This, pSourceTexture, pDestinationTexture);
4893 hr = WINED3DERR_INVALIDCALL;
4896 if (pSourceTexture == pDestinationTexture) {
4897 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4898 This, pSourceTexture, pDestinationTexture);
4899 hr = WINED3DERR_INVALIDCALL;
4901 /* Verify that the source and destination textures are the same type */
4902 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4903 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4905 if (sourceType != destinationType) {
4906 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
4907 This);
4908 hr = WINED3DERR_INVALIDCALL;
4911 /* check that both textures have the identical numbers of levels */
4912 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
4913 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
4914 hr = WINED3DERR_INVALIDCALL;
4917 if (WINED3D_OK == hr) {
4919 /* Make sure that the destination texture is loaded */
4920 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
4922 /* Update every surface level of the texture */
4923 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
4925 switch (sourceType) {
4926 case WINED3DRTYPE_TEXTURE:
4928 IWineD3DSurface *srcSurface;
4929 IWineD3DSurface *destSurface;
4931 for (i = 0 ; i < levels ; ++i) {
4932 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
4933 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
4934 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4935 IWineD3DSurface_Release(srcSurface);
4936 IWineD3DSurface_Release(destSurface);
4937 if (WINED3D_OK != hr) {
4938 WARN("(%p) : Call to update surface failed\n", This);
4939 return hr;
4943 break;
4944 case WINED3DRTYPE_CUBETEXTURE:
4946 IWineD3DSurface *srcSurface;
4947 IWineD3DSurface *destSurface;
4948 WINED3DCUBEMAP_FACES faceType;
4950 for (i = 0 ; i < levels ; ++i) {
4951 /* Update each cube face */
4952 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
4953 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
4954 if (WINED3D_OK != hr) {
4955 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4956 } else {
4957 TRACE("Got srcSurface %p\n", srcSurface);
4959 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
4960 if (WINED3D_OK != hr) {
4961 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
4962 } else {
4963 TRACE("Got desrSurface %p\n", destSurface);
4965 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
4966 IWineD3DSurface_Release(srcSurface);
4967 IWineD3DSurface_Release(destSurface);
4968 if (WINED3D_OK != hr) {
4969 WARN("(%p) : Call to update surface failed\n", This);
4970 return hr;
4975 break;
4976 #if 0 /* TODO: Add support for volume textures */
4977 case WINED3DRTYPE_VOLUMETEXTURE:
4979 IWineD3DVolume srcVolume = NULL;
4980 IWineD3DSurface destVolume = NULL;
4982 for (i = 0 ; i < levels ; ++i) {
4983 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
4984 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
4985 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
4986 IWineD3DVolume_Release(srcSurface);
4987 IWineD3DVolume_Release(destSurface);
4988 if (WINED3D_OK != hr) {
4989 WARN("(%p) : Call to update volume failed\n", This);
4990 return hr;
4994 break;
4995 #endif
4996 default:
4997 FIXME("(%p) : Unsupported source and destination type\n", This);
4998 hr = WINED3DERR_INVALIDCALL;
5002 return hr;
5005 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5006 IWineD3DSwapChain *swapChain;
5007 HRESULT hr;
5008 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5009 if(hr == WINED3D_OK) {
5010 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5011 IWineD3DSwapChain_Release(swapChain);
5013 return hr;
5016 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5018 /* return a sensible default */
5019 *pNumPasses = 1;
5020 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5021 FIXME("(%p) : stub\n", This);
5022 return WINED3D_OK;
5025 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5027 int j;
5028 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5029 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5030 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5031 return WINED3DERR_INVALIDCALL;
5033 for (j = 0; j < 256; ++j) {
5034 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5035 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5036 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5037 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5039 TRACE("(%p) : returning\n", This);
5040 return WINED3D_OK;
5043 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5045 int j;
5046 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5047 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5048 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5049 return WINED3DERR_INVALIDCALL;
5051 for (j = 0; j < 256; ++j) {
5052 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5053 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5054 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5055 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5057 TRACE("(%p) : returning\n", This);
5058 return WINED3D_OK;
5061 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5063 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5064 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5065 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5066 return WINED3DERR_INVALIDCALL;
5068 /*TODO: stateblocks */
5069 This->currentPalette = PaletteNumber;
5070 TRACE("(%p) : returning\n", This);
5071 return WINED3D_OK;
5074 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5076 if (PaletteNumber == NULL) {
5077 WARN("(%p) : returning Invalid Call\n", This);
5078 return WINED3DERR_INVALIDCALL;
5080 /*TODO: stateblocks */
5081 *PaletteNumber = This->currentPalette;
5082 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5083 return WINED3D_OK;
5086 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5088 static BOOL showFixmes = TRUE;
5089 if (showFixmes) {
5090 FIXME("(%p) : stub\n", This);
5091 showFixmes = FALSE;
5094 This->softwareVertexProcessing = bSoftware;
5095 return WINED3D_OK;
5099 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5101 static BOOL showFixmes = TRUE;
5102 if (showFixmes) {
5103 FIXME("(%p) : stub\n", This);
5104 showFixmes = FALSE;
5106 return This->softwareVertexProcessing;
5110 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5112 IWineD3DSwapChain *swapChain;
5113 HRESULT hr;
5115 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5117 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5118 if(hr == WINED3D_OK){
5119 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5120 IWineD3DSwapChain_Release(swapChain);
5121 }else{
5122 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5124 return hr;
5128 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5130 static BOOL showfixmes = TRUE;
5131 if(nSegments != 0.0f) {
5132 if( showfixmes) {
5133 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5134 showfixmes = FALSE;
5137 return WINED3D_OK;
5140 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 static BOOL showfixmes = TRUE;
5143 if( showfixmes) {
5144 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5145 showfixmes = FALSE;
5147 return 0.0f;
5150 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5151 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5152 /** TODO: remove casts to IWineD3DSurfaceImpl
5153 * NOTE: move code to surface to accomplish this
5154 ****************************************/
5155 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5156 int srcWidth, srcHeight;
5157 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5158 WINED3DFORMAT destFormat, srcFormat;
5159 UINT destSize;
5160 int srcLeft, destLeft, destTop;
5161 WINED3DPOOL srcPool, destPool;
5162 int offset = 0;
5163 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5164 glDescriptor *glDescription = NULL;
5165 GLenum dummy;
5166 int bpp;
5167 CONVERT_TYPES convert = NO_CONVERSION;
5169 WINED3DSURFACE_DESC winedesc;
5171 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5172 memset(&winedesc, 0, sizeof(winedesc));
5173 winedesc.Width = &srcSurfaceWidth;
5174 winedesc.Height = &srcSurfaceHeight;
5175 winedesc.Pool = &srcPool;
5176 winedesc.Format = &srcFormat;
5178 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5180 winedesc.Width = &destSurfaceWidth;
5181 winedesc.Height = &destSurfaceHeight;
5182 winedesc.Pool = &destPool;
5183 winedesc.Format = &destFormat;
5184 winedesc.Size = &destSize;
5186 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5188 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5189 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5190 return WINED3DERR_INVALIDCALL;
5193 /* This call loads the opengl surface directly, instead of copying the surface to the
5194 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5195 * copy in sysmem and use regular surface loading.
5197 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5198 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5199 if(convert != NO_CONVERSION) {
5200 return IWineD3DSurface_BltFast(pDestinationSurface,
5201 pDestPoint ? pDestPoint->x : 0,
5202 pDestPoint ? pDestPoint->y : 0,
5203 pSourceSurface, (RECT *) pSourceRect, 0);
5206 if (destFormat == WINED3DFMT_UNKNOWN) {
5207 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5208 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5210 /* Get the update surface description */
5211 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5214 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5216 ENTER_GL();
5218 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5219 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5220 checkGLcall("glActiveTextureARB");
5223 /* Make sure the surface is loaded and up to date */
5224 IWineD3DSurface_PreLoad(pDestinationSurface);
5226 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5228 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5229 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5230 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5231 srcLeft = pSourceRect ? pSourceRect->left : 0;
5232 destLeft = pDestPoint ? pDestPoint->x : 0;
5233 destTop = pDestPoint ? pDestPoint->y : 0;
5236 /* This function doesn't support compressed textures
5237 the pitch is just bytesPerPixel * width */
5238 if(srcWidth != srcSurfaceWidth || srcLeft ){
5239 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5240 offset += srcLeft * pSrcSurface->bytesPerPixel;
5241 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5243 /* TODO DXT formats */
5245 if(pSourceRect != NULL && pSourceRect->top != 0){
5246 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5248 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5249 ,This
5250 ,glDescription->level
5251 ,destLeft
5252 ,destTop
5253 ,srcWidth
5254 ,srcHeight
5255 ,glDescription->glFormat
5256 ,glDescription->glType
5257 ,IWineD3DSurface_GetData(pSourceSurface)
5260 /* Sanity check */
5261 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5263 /* need to lock the surface to get the data */
5264 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5267 /* TODO: Cube and volume support */
5268 if(rowoffset != 0){
5269 /* not a whole row so we have to do it a line at a time */
5270 int j;
5272 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5273 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5275 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5277 glTexSubImage2D(glDescription->target
5278 ,glDescription->level
5279 ,destLeft
5281 ,srcWidth
5283 ,glDescription->glFormat
5284 ,glDescription->glType
5285 ,data /* could be quicker using */
5287 data += rowoffset;
5290 } else { /* Full width, so just write out the whole texture */
5292 if (WINED3DFMT_DXT1 == destFormat ||
5293 WINED3DFMT_DXT2 == destFormat ||
5294 WINED3DFMT_DXT3 == destFormat ||
5295 WINED3DFMT_DXT4 == destFormat ||
5296 WINED3DFMT_DXT5 == destFormat) {
5297 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5298 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5299 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5300 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5301 } if (destFormat != srcFormat) {
5302 FIXME("Updating mixed format compressed texture is not curretly support\n");
5303 } else {
5304 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5305 glDescription->level,
5306 glDescription->glFormatInternal,
5307 srcWidth,
5308 srcHeight,
5310 destSize,
5311 IWineD3DSurface_GetData(pSourceSurface));
5313 } else {
5314 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5318 } else {
5319 glTexSubImage2D(glDescription->target
5320 ,glDescription->level
5321 ,destLeft
5322 ,destTop
5323 ,srcWidth
5324 ,srcHeight
5325 ,glDescription->glFormat
5326 ,glDescription->glType
5327 ,IWineD3DSurface_GetData(pSourceSurface)
5331 checkGLcall("glTexSubImage2D");
5333 LEAVE_GL();
5335 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5336 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5337 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5339 return WINED3D_OK;
5342 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5344 struct WineD3DRectPatch *patch;
5345 unsigned int i;
5346 struct list *e;
5347 BOOL found;
5348 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5350 if(!(Handle || pRectPatchInfo)) {
5351 /* TODO: Write a test for the return value, thus the FIXME */
5352 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5353 return WINED3DERR_INVALIDCALL;
5356 if(Handle) {
5357 i = PATCHMAP_HASHFUNC(Handle);
5358 found = FALSE;
5359 LIST_FOR_EACH(e, &This->patches[i]) {
5360 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5361 if(patch->Handle == Handle) {
5362 found = TRUE;
5363 break;
5367 if(!found) {
5368 TRACE("Patch does not exist. Creating a new one\n");
5369 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5370 patch->Handle = Handle;
5371 list_add_head(&This->patches[i], &patch->entry);
5372 } else {
5373 TRACE("Found existing patch %p\n", patch);
5375 } else {
5376 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5377 * attributes we have to tesselate, read back, and draw. This needs a patch
5378 * management structure instance. Create one.
5380 * A possible improvement is to check if a vertex shader is used, and if not directly
5381 * draw the patch.
5383 FIXME("Drawing an uncached patch. This is slow\n");
5384 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5387 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5388 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5389 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5390 HRESULT hr;
5391 TRACE("Tesselation density or patch info changed, retesselating\n");
5393 if(pRectPatchInfo) {
5394 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5396 patch->numSegs[0] = pNumSegs[0];
5397 patch->numSegs[1] = pNumSegs[1];
5398 patch->numSegs[2] = pNumSegs[2];
5399 patch->numSegs[3] = pNumSegs[3];
5401 hr = tesselate_rectpatch(This, patch);
5402 if(FAILED(hr)) {
5403 WARN("Patch tesselation failed\n");
5405 /* Do not release the handle to store the params of the patch */
5406 if(!Handle) {
5407 HeapFree(GetProcessHeap(), 0, patch);
5409 return hr;
5413 This->currentPatch = patch;
5414 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5415 This->currentPatch = NULL;
5417 /* Destroy uncached patches */
5418 if(!Handle) {
5419 HeapFree(GetProcessHeap(), 0, patch->mem);
5420 HeapFree(GetProcessHeap(), 0, patch);
5422 return WINED3D_OK;
5425 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5426 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5428 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5429 FIXME("(%p) : Stub\n", This);
5430 return WINED3D_OK;
5433 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5435 int i;
5436 struct WineD3DRectPatch *patch;
5437 struct list *e;
5438 TRACE("(%p) Handle(%d)\n", This, Handle);
5440 i = PATCHMAP_HASHFUNC(Handle);
5441 LIST_FOR_EACH(e, &This->patches[i]) {
5442 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5443 if(patch->Handle == Handle) {
5444 TRACE("Deleting patch %p\n", patch);
5445 list_remove(&patch->entry);
5446 HeapFree(GetProcessHeap(), 0, patch->mem);
5447 HeapFree(GetProcessHeap(), 0, patch);
5448 return WINED3D_OK;
5452 /* TODO: Write a test for the return value */
5453 FIXME("Attempt to destroy nonexistant patch\n");
5454 return WINED3DERR_INVALIDCALL;
5457 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5458 HRESULT hr;
5459 IWineD3DSwapChain *swapchain;
5461 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5462 if (SUCCEEDED(hr)) {
5463 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5464 return swapchain;
5467 return NULL;
5470 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5473 if (!*fbo) {
5474 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5475 checkGLcall("glGenFramebuffersEXT()");
5477 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5478 checkGLcall("glBindFramebuffer()");
5481 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5482 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5483 IWineD3DBaseTextureImpl *texture_impl;
5484 GLenum texttarget, target;
5485 GLint old_binding;
5487 texttarget = surface_impl->glDescription.target;
5488 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5489 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5491 IWineD3DSurface_PreLoad(surface);
5493 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5494 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5495 glBindTexture(target, old_binding);
5497 /* Update base texture states array */
5498 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5499 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5500 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5501 if (texture_impl->baseTexture.bindCount) {
5502 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5505 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5508 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5509 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5511 checkGLcall("attach_surface_fbo");
5514 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5516 IWineD3DSwapChain *swapchain;
5518 swapchain = get_swapchain(surface);
5519 if (swapchain) {
5520 GLenum buffer;
5522 TRACE("Surface %p is onscreen\n", surface);
5524 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5525 buffer = surface_get_gl_buffer(surface, swapchain);
5526 glDrawBuffer(buffer);
5527 checkGLcall("glDrawBuffer()");
5528 } else {
5529 TRACE("Surface %p is offscreen\n", surface);
5530 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5531 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5534 if (rect) {
5535 glEnable(GL_SCISSOR_TEST);
5536 if(!swapchain) {
5537 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5538 } else {
5539 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5540 rect->x2 - rect->x1, rect->y2 - rect->y1);
5542 checkGLcall("glScissor");
5543 } else {
5544 glDisable(GL_SCISSOR_TEST);
5546 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5548 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5551 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5552 glClear(GL_COLOR_BUFFER_BIT);
5553 checkGLcall("glClear");
5555 if (This->render_offscreen) {
5556 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5557 } else {
5558 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5559 checkGLcall("glBindFramebuffer()");
5562 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5563 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5564 glDrawBuffer(GL_BACK);
5565 checkGLcall("glDrawBuffer()");
5569 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5571 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5572 WINEDDBLTFX BltFx;
5573 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5575 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5576 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5577 return WINED3DERR_INVALIDCALL;
5580 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5581 color_fill_fbo(iface, pSurface, pRect, color);
5582 return WINED3D_OK;
5583 } else {
5584 /* Just forward this to the DirectDraw blitting engine */
5585 memset(&BltFx, 0, sizeof(BltFx));
5586 BltFx.dwSize = sizeof(BltFx);
5587 BltFx.u5.dwFillColor = color;
5588 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5592 /* rendertarget and deptth stencil functions */
5593 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5596 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5597 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5598 return WINED3DERR_INVALIDCALL;
5601 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5602 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5603 /* Note inc ref on returned surface */
5604 if(*ppRenderTarget != NULL)
5605 IWineD3DSurface_AddRef(*ppRenderTarget);
5606 return WINED3D_OK;
5609 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5612 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5613 IWineD3DSwapChainImpl *Swapchain;
5614 HRESULT hr;
5616 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5618 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5619 if(hr != WINED3D_OK) {
5620 ERR("Can't get the swapchain\n");
5621 return hr;
5624 /* Make sure to release the swapchain */
5625 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5627 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5628 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5629 return WINED3DERR_INVALIDCALL;
5631 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5632 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5633 return WINED3DERR_INVALIDCALL;
5636 if(Swapchain->frontBuffer != Front) {
5637 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5639 if(Swapchain->frontBuffer)
5640 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5641 Swapchain->frontBuffer = Front;
5643 if(Swapchain->frontBuffer) {
5644 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5648 if(Back && !Swapchain->backBuffer) {
5649 /* We need memory for the back buffer array - only one back buffer this way */
5650 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5651 if(!Swapchain->backBuffer) {
5652 ERR("Out of memory\n");
5653 return E_OUTOFMEMORY;
5657 if(Swapchain->backBuffer[0] != Back) {
5658 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5660 /* What to do about the context here in the case of multithreading? Not sure.
5661 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5663 ENTER_GL();
5664 if(!Swapchain->backBuffer[0]) {
5665 /* GL was told to draw to the front buffer at creation,
5666 * undo that
5668 glDrawBuffer(GL_BACK);
5669 checkGLcall("glDrawBuffer(GL_BACK)");
5670 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5671 Swapchain->presentParms.BackBufferCount = 1;
5672 } else if (!Back) {
5673 /* That makes problems - disable for now */
5674 /* glDrawBuffer(GL_FRONT); */
5675 checkGLcall("glDrawBuffer(GL_FRONT)");
5676 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5677 Swapchain->presentParms.BackBufferCount = 0;
5679 LEAVE_GL();
5681 if(Swapchain->backBuffer[0])
5682 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5683 Swapchain->backBuffer[0] = Back;
5685 if(Swapchain->backBuffer[0]) {
5686 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5687 } else {
5688 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 *ppZStencilSurface = This->depthStencilBuffer;
5699 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5701 if(*ppZStencilSurface != NULL) {
5702 /* Note inc ref on returned surface */
5703 IWineD3DSurface_AddRef(*ppZStencilSurface);
5705 return WINED3D_OK;
5708 /* TODO: Handle stencil attachments */
5709 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5711 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5713 TRACE("Set depth stencil to %p\n", depth_stencil);
5715 if (depth_stencil_impl) {
5716 if (depth_stencil_impl->current_renderbuffer) {
5717 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5718 checkGLcall("glFramebufferRenderbufferEXT()");
5719 } else {
5720 IWineD3DBaseTextureImpl *texture_impl;
5721 GLenum texttarget, target;
5722 GLint old_binding = 0;
5724 texttarget = depth_stencil_impl->glDescription.target;
5725 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5726 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5728 IWineD3DSurface_PreLoad(depth_stencil);
5730 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5731 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5732 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5733 glBindTexture(target, old_binding);
5735 /* Update base texture states array */
5736 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5737 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5738 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5739 if (texture_impl->baseTexture.bindCount) {
5740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5743 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5746 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5747 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5748 checkGLcall("glFramebufferTexture2DEXT()");
5750 } else {
5751 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5752 checkGLcall("glFramebufferTexture2DEXT()");
5756 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5758 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5760 TRACE("Set render target %u to %p\n", idx, render_target);
5762 if (rtimpl) {
5763 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5764 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5765 } else {
5766 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5767 checkGLcall("glFramebufferTexture2DEXT()");
5769 This->draw_buffers[idx] = GL_NONE;
5773 static void check_fbo_status(IWineD3DDevice *iface) {
5774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5775 GLenum status;
5777 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5778 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5779 TRACE("FBO complete\n");
5780 } else {
5781 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5783 /* Dump the FBO attachments */
5784 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5785 IWineD3DSurfaceImpl *attachment;
5786 int i;
5788 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5789 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5790 if (attachment) {
5791 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5792 attachment->pow2Width, attachment->pow2Height);
5795 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5796 if (attachment) {
5797 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5798 attachment->pow2Width, attachment->pow2Height);
5804 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5806 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5807 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5809 if (!ds_impl) return FALSE;
5811 if (ds_impl->current_renderbuffer) {
5812 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5813 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5816 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5817 rt_impl->pow2Height != ds_impl->pow2Height);
5820 void apply_fbo_state(IWineD3DDevice *iface) {
5821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5822 unsigned int i;
5824 if (This->render_offscreen) {
5825 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5827 /* Apply render targets */
5828 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5829 IWineD3DSurface *render_target = This->render_targets[i];
5830 if (This->fbo_color_attachments[i] != render_target) {
5831 set_render_target_fbo(iface, i, render_target);
5832 This->fbo_color_attachments[i] = render_target;
5836 /* Apply depth targets */
5837 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5838 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5839 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5841 if (This->stencilBufferTarget) {
5842 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5844 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5845 This->fbo_depth_attachment = This->stencilBufferTarget;
5848 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5849 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5850 checkGLcall("glDrawBuffers()");
5851 } else {
5852 glDrawBuffer(This->draw_buffers[0]);
5853 checkGLcall("glDrawBuffer()");
5855 } else {
5856 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5859 check_fbo_status(iface);
5862 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5863 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5865 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5866 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5867 GLenum gl_filter;
5869 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5870 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5871 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5872 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5874 switch (filter) {
5875 case WINED3DTEXF_LINEAR:
5876 gl_filter = GL_LINEAR;
5877 break;
5879 default:
5880 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5881 case WINED3DTEXF_NONE:
5882 case WINED3DTEXF_POINT:
5883 gl_filter = GL_NEAREST;
5884 break;
5887 /* Attach src surface to src fbo */
5888 src_swapchain = get_swapchain(src_surface);
5889 if (src_swapchain) {
5890 GLenum buffer;
5892 TRACE("Source surface %p is onscreen\n", src_surface);
5893 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5895 ENTER_GL();
5896 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5897 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5898 glReadBuffer(buffer);
5899 checkGLcall("glReadBuffer()");
5901 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5902 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5903 } else {
5904 TRACE("Source surface %p is offscreen\n", src_surface);
5905 ENTER_GL();
5906 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
5907 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
5908 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
5909 checkGLcall("glReadBuffer()");
5911 LEAVE_GL();
5913 /* Attach dst surface to dst fbo */
5914 dst_swapchain = get_swapchain(dst_surface);
5915 if (dst_swapchain) {
5916 GLenum buffer;
5918 TRACE("Destination surface %p is onscreen\n", dst_surface);
5919 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
5921 ENTER_GL();
5922 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
5923 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
5924 glDrawBuffer(buffer);
5925 checkGLcall("glDrawBuffer()");
5927 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
5928 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
5929 } else {
5930 TRACE("Destination surface %p is offscreen\n", dst_surface);
5932 /* No src or dst swapchain? Make sure some context is active(multithreading) */
5933 if(!src_swapchain) {
5934 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5937 ENTER_GL();
5938 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
5939 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
5940 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
5941 checkGLcall("glDrawBuffer()");
5943 glDisable(GL_SCISSOR_TEST);
5944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5946 if (flip) {
5947 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5948 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
5949 checkGLcall("glBlitFramebuffer()");
5950 } else {
5951 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
5952 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
5953 checkGLcall("glBlitFramebuffer()");
5956 if (This->render_offscreen) {
5957 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5958 } else {
5959 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5960 checkGLcall("glBindFramebuffer()");
5963 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
5964 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
5965 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
5966 glDrawBuffer(GL_BACK);
5967 checkGLcall("glDrawBuffer()");
5969 LEAVE_GL();
5972 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5974 WINED3DVIEWPORT viewport;
5976 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
5978 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5979 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5980 return WINED3DERR_INVALIDCALL;
5983 /* MSDN says that null disables the render target
5984 but a device must always be associated with a render target
5985 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
5987 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
5988 for more details
5990 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
5991 FIXME("Trying to set render target 0 to NULL\n");
5992 return WINED3DERR_INVALIDCALL;
5994 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
5995 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);
5996 return WINED3DERR_INVALIDCALL;
5999 /* If we are trying to set what we already have, don't bother */
6000 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6001 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6002 return WINED3D_OK;
6004 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6005 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6006 This->render_targets[RenderTargetIndex] = pRenderTarget;
6008 /* Render target 0 is special */
6009 if(RenderTargetIndex == 0) {
6010 /* Finally, reset the viewport as the MSDN states. */
6011 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6012 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6013 viewport.X = 0;
6014 viewport.Y = 0;
6015 viewport.MaxZ = 1.0f;
6016 viewport.MinZ = 0.0f;
6017 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6018 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6019 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6021 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6023 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6024 * ctx properly.
6025 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6026 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6028 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6030 return WINED3D_OK;
6033 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6035 HRESULT hr = WINED3D_OK;
6036 IWineD3DSurface *tmp;
6038 TRACE("(%p) Swapping z-buffer\n",This);
6040 if (pNewZStencil == This->stencilBufferTarget) {
6041 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6042 } else {
6043 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6044 * depending on the renter target implementation being used.
6045 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6046 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6047 * stencil buffer and incure an extra memory overhead
6048 ******************************************************/
6050 tmp = This->stencilBufferTarget;
6051 This->stencilBufferTarget = pNewZStencil;
6052 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6053 /* should we be calling the parent or the wined3d surface? */
6054 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6055 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6056 hr = WINED3D_OK;
6058 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6059 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6066 return hr;
6069 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6070 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6072 /* TODO: the use of Impl is deprecated. */
6073 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6074 WINED3DLOCKED_RECT lockedRect;
6076 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6078 /* some basic validation checks */
6079 if(This->cursorTexture) {
6080 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6081 ENTER_GL();
6082 glDeleteTextures(1, &This->cursorTexture);
6083 LEAVE_GL();
6084 This->cursorTexture = 0;
6087 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6088 This->haveHardwareCursor = TRUE;
6089 else
6090 This->haveHardwareCursor = FALSE;
6092 if(pCursorBitmap) {
6093 WINED3DLOCKED_RECT rect;
6095 /* MSDN: Cursor must be A8R8G8B8 */
6096 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6097 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6098 return WINED3DERR_INVALIDCALL;
6101 /* MSDN: Cursor must be smaller than the display mode */
6102 if(pSur->currentDesc.Width > This->ddraw_width ||
6103 pSur->currentDesc.Height > This->ddraw_height) {
6104 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);
6105 return WINED3DERR_INVALIDCALL;
6108 if (!This->haveHardwareCursor) {
6109 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6111 /* Do not store the surface's pointer because the application may
6112 * release it after setting the cursor image. Windows doesn't
6113 * addref the set surface, so we can't do this either without
6114 * creating circular refcount dependencies. Copy out the gl texture
6115 * instead.
6117 This->cursorWidth = pSur->currentDesc.Width;
6118 This->cursorHeight = pSur->currentDesc.Height;
6119 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6121 const GlPixelFormatDesc *glDesc;
6122 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6123 char *mem, *bits = (char *)rect.pBits;
6124 GLint intfmt = glDesc->glInternal;
6125 GLint format = glDesc->glFormat;
6126 GLint type = glDesc->glType;
6127 INT height = This->cursorHeight;
6128 INT width = This->cursorWidth;
6129 INT bpp = tableEntry->bpp;
6130 INT i;
6132 /* Reformat the texture memory (pitch and width can be
6133 * different) */
6134 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6135 for(i = 0; i < height; i++)
6136 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6137 IWineD3DSurface_UnlockRect(pCursorBitmap);
6138 ENTER_GL();
6140 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6141 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6142 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6145 /* Make sure that a proper texture unit is selected */
6146 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6147 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6148 checkGLcall("glActiveTextureARB");
6150 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6151 /* Create a new cursor texture */
6152 glGenTextures(1, &This->cursorTexture);
6153 checkGLcall("glGenTextures");
6154 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6155 checkGLcall("glBindTexture");
6156 /* Copy the bitmap memory into the cursor texture */
6157 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6158 HeapFree(GetProcessHeap(), 0, mem);
6159 checkGLcall("glTexImage2D");
6161 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6162 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6163 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6166 LEAVE_GL();
6168 else
6170 FIXME("A cursor texture was not returned.\n");
6171 This->cursorTexture = 0;
6174 else
6176 /* Draw a hardware cursor */
6177 ICONINFO cursorInfo;
6178 HCURSOR cursor;
6179 /* Create and clear maskBits because it is not needed for
6180 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6181 * chunks. */
6182 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6183 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6184 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6185 WINED3DLOCK_NO_DIRTY_UPDATE |
6186 WINED3DLOCK_READONLY
6188 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6189 pSur->currentDesc.Height);
6191 cursorInfo.fIcon = FALSE;
6192 cursorInfo.xHotspot = XHotSpot;
6193 cursorInfo.yHotspot = YHotSpot;
6194 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6195 pSur->currentDesc.Height, 1,
6196 1, &maskBits);
6197 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6198 pSur->currentDesc.Height, 1,
6199 32, lockedRect.pBits);
6200 IWineD3DSurface_UnlockRect(pCursorBitmap);
6201 /* Create our cursor and clean up. */
6202 cursor = CreateIconIndirect(&cursorInfo);
6203 SetCursor(cursor);
6204 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6205 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6206 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6207 This->hardwareCursor = cursor;
6208 HeapFree(GetProcessHeap(), 0, maskBits);
6212 This->xHotSpot = XHotSpot;
6213 This->yHotSpot = YHotSpot;
6214 return WINED3D_OK;
6217 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6219 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6221 This->xScreenSpace = XScreenSpace;
6222 This->yScreenSpace = YScreenSpace;
6224 return;
6228 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6230 BOOL oldVisible = This->bCursorVisible;
6231 POINT pt;
6233 TRACE("(%p) : visible(%d)\n", This, bShow);
6236 * When ShowCursor is first called it should make the cursor appear at the OS's last
6237 * known cursor position. Because of this, some applications just repetitively call
6238 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6240 GetCursorPos(&pt);
6241 This->xScreenSpace = pt.x;
6242 This->yScreenSpace = pt.y;
6244 if (This->haveHardwareCursor) {
6245 This->bCursorVisible = bShow;
6246 if (bShow)
6247 SetCursor(This->hardwareCursor);
6248 else
6249 SetCursor(NULL);
6251 else
6253 if (This->cursorTexture)
6254 This->bCursorVisible = bShow;
6257 return oldVisible;
6260 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6262 TRACE("(%p) : state (%u)\n", This, This->state);
6263 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6264 switch (This->state) {
6265 case WINED3D_OK:
6266 return WINED3D_OK;
6267 case WINED3DERR_DEVICELOST:
6269 ResourceList *resourceList = This->resources;
6270 while (NULL != resourceList) {
6271 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6272 return WINED3DERR_DEVICENOTRESET;
6273 resourceList = resourceList->next;
6275 return WINED3DERR_DEVICELOST;
6277 case WINED3DERR_DRIVERINTERNALERROR:
6278 return WINED3DERR_DRIVERINTERNALERROR;
6281 /* Unknown state */
6282 return WINED3DERR_DRIVERINTERNALERROR;
6286 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6288 /** FIXME: Resource tracking needs to be done,
6289 * The closes we can do to this is set the priorities of all managed textures low
6290 * and then reset them.
6291 ***********************************************************/
6292 FIXME("(%p) : stub\n", This);
6293 return WINED3D_OK;
6296 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6297 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6299 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6300 if(surface->Flags & SFLAG_DIBSECTION) {
6301 /* Release the DC */
6302 SelectObject(surface->hDC, surface->dib.holdbitmap);
6303 DeleteDC(surface->hDC);
6304 /* Release the DIB section */
6305 DeleteObject(surface->dib.DIBsection);
6306 surface->dib.bitmap_data = NULL;
6307 surface->resource.allocatedMemory = NULL;
6308 surface->Flags &= ~SFLAG_DIBSECTION;
6310 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6311 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6312 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6313 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6314 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6315 } else {
6316 surface->pow2Width = surface->pow2Height = 1;
6317 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6318 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6320 if(surface->glDescription.textureName) {
6321 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6322 ENTER_GL();
6323 glDeleteTextures(1, &surface->glDescription.textureName);
6324 LEAVE_GL();
6325 surface->glDescription.textureName = 0;
6326 surface->Flags &= ~SFLAG_CLIENT;
6328 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6329 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6330 surface->Flags |= SFLAG_NONPOW2;
6331 } else {
6332 surface->Flags &= ~SFLAG_NONPOW2;
6334 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6335 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6338 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6340 IWineD3DSwapChainImpl *swapchain;
6341 HRESULT hr;
6342 BOOL DisplayModeChanged = FALSE;
6343 WINED3DDISPLAYMODE mode;
6344 TRACE("(%p)\n", This);
6346 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6347 if(FAILED(hr)) {
6348 ERR("Failed to get the first implicit swapchain\n");
6349 return hr;
6352 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6353 * on an existing gl context, so there's no real need for recreation.
6355 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6357 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6359 TRACE("New params:\n");
6360 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6361 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6362 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6363 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6364 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6365 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6366 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6367 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6368 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6369 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6370 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6371 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6372 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6374 /* No special treatment of these parameters. Just store them */
6375 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6376 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6377 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6378 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6380 /* What to do about these? */
6381 if(pPresentationParameters->BackBufferCount != 0 &&
6382 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6383 ERR("Cannot change the back buffer count yet\n");
6385 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6386 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6387 ERR("Cannot change the back buffer format yet\n");
6389 if(pPresentationParameters->hDeviceWindow != NULL &&
6390 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6391 ERR("Cannot change the device window yet\n");
6393 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6394 ERR("What do do about a changed auto depth stencil parameter?\n");
6397 if(pPresentationParameters->Windowed) {
6398 mode.Width = swapchain->orig_width;
6399 mode.Height = swapchain->orig_height;
6400 mode.RefreshRate = 0;
6401 mode.Format = swapchain->presentParms.BackBufferFormat;
6402 } else {
6403 mode.Width = pPresentationParameters->BackBufferWidth;
6404 mode.Height = pPresentationParameters->BackBufferHeight;
6405 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6406 mode.Format = swapchain->presentParms.BackBufferFormat;
6409 /* Should Width == 800 && Height == 0 set 800x600? */
6410 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6411 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6412 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6414 WINED3DVIEWPORT vp;
6415 int i;
6417 vp.X = 0;
6418 vp.Y = 0;
6419 vp.Width = pPresentationParameters->BackBufferWidth;
6420 vp.Height = pPresentationParameters->BackBufferHeight;
6421 vp.MinZ = 0;
6422 vp.MaxZ = 1;
6424 if(!pPresentationParameters->Windowed) {
6425 DisplayModeChanged = TRUE;
6427 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6428 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6430 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6431 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6432 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6435 /* Now set the new viewport */
6436 IWineD3DDevice_SetViewport(iface, &vp);
6439 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6440 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6441 DisplayModeChanged) {
6443 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6444 if(!pPresentationParameters->Windowed) {
6445 IWineD3DDevice_SetFullscreen(iface, TRUE);
6448 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6450 /* Switching out of fullscreen mode? First set the original res, then change the window */
6451 if(pPresentationParameters->Windowed) {
6452 IWineD3DDevice_SetFullscreen(iface, FALSE);
6454 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6457 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6458 return WINED3D_OK;
6461 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6463 /** FIXME: always true at the moment **/
6464 if(!bEnableDialogs) {
6465 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6467 return WINED3D_OK;
6471 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6473 TRACE("(%p) : pParameters %p\n", This, pParameters);
6475 *pParameters = This->createParms;
6476 return WINED3D_OK;
6479 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6480 IWineD3DSwapChain *swapchain;
6481 HRESULT hrc = WINED3D_OK;
6483 TRACE("Relaying to swapchain\n");
6485 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6486 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6487 IWineD3DSwapChain_Release(swapchain);
6489 return;
6492 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6493 IWineD3DSwapChain *swapchain;
6494 HRESULT hrc = WINED3D_OK;
6496 TRACE("Relaying to swapchain\n");
6498 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6499 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6500 IWineD3DSwapChain_Release(swapchain);
6502 return;
6506 /** ********************************************************
6507 * Notification functions
6508 ** ********************************************************/
6509 /** This function must be called in the release of a resource when ref == 0,
6510 * the contents of resource must still be correct,
6511 * any handels to other resource held by the caller must be closed
6512 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6513 *****************************************************/
6514 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6516 ResourceList* resourceList;
6518 TRACE("(%p) : resource %p\n", This, resource);
6519 /* add a new texture to the frot of the linked list */
6520 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6521 resourceList->resource = resource;
6523 /* Get the old head */
6524 resourceList->next = This->resources;
6526 This->resources = resourceList;
6527 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6529 return;
6532 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6534 ResourceList* resourceList = NULL;
6535 ResourceList* previousResourceList = NULL;
6537 TRACE("(%p) : resource %p\n", This, resource);
6539 resourceList = This->resources;
6541 while (resourceList != NULL) {
6542 if(resourceList->resource == resource) break;
6543 previousResourceList = resourceList;
6544 resourceList = resourceList->next;
6547 if (resourceList == NULL) {
6548 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6549 return;
6550 } else {
6551 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6553 /* make sure we don't leave a hole in the list */
6554 if (previousResourceList != NULL) {
6555 previousResourceList->next = resourceList->next;
6556 } else {
6557 This->resources = resourceList->next;
6560 return;
6564 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6566 int counter;
6568 TRACE("(%p) : resource %p\n", This, resource);
6569 switch(IWineD3DResource_GetType(resource)){
6570 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6571 case WINED3DRTYPE_SURFACE: {
6572 unsigned int i;
6574 /* Cleanup any FBO attachments if d3d is enabled */
6575 if(This->d3d_initialized) {
6576 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6577 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6578 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6579 set_render_target_fbo(iface, i, NULL);
6580 This->fbo_color_attachments[i] = NULL;
6583 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6584 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6585 set_depth_stencil_fbo(iface, NULL);
6586 This->fbo_depth_attachment = NULL;
6590 break;
6592 case WINED3DRTYPE_TEXTURE:
6593 case WINED3DRTYPE_CUBETEXTURE:
6594 case WINED3DRTYPE_VOLUMETEXTURE:
6595 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6596 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6597 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6598 This->stateBlock->textures[counter] = NULL;
6600 if (This->updateStateBlock != This->stateBlock ){
6601 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6602 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6603 This->updateStateBlock->textures[counter] = NULL;
6607 break;
6608 case WINED3DRTYPE_VOLUME:
6609 /* TODO: nothing really? */
6610 break;
6611 case WINED3DRTYPE_VERTEXBUFFER:
6612 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6614 int streamNumber;
6615 TRACE("Cleaning up stream pointers\n");
6617 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6618 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6619 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6621 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6622 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6623 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6624 This->updateStateBlock->streamSource[streamNumber] = 0;
6625 /* Set changed flag? */
6628 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) */
6629 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6630 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6631 This->stateBlock->streamSource[streamNumber] = 0;
6634 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6635 else { /* This shouldn't happen */
6636 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6638 #endif
6642 break;
6643 case WINED3DRTYPE_INDEXBUFFER:
6644 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6645 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6646 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6647 This->updateStateBlock->pIndexData = NULL;
6650 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6651 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6652 This->stateBlock->pIndexData = NULL;
6656 break;
6657 default:
6658 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6659 break;
6663 /* Remove the resoruce from the resourceStore */
6664 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6666 TRACE("Resource released\n");
6670 /**********************************************************
6671 * IWineD3DDevice VTbl follows
6672 **********************************************************/
6674 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6676 /*** IUnknown methods ***/
6677 IWineD3DDeviceImpl_QueryInterface,
6678 IWineD3DDeviceImpl_AddRef,
6679 IWineD3DDeviceImpl_Release,
6680 /*** IWineD3DDevice methods ***/
6681 IWineD3DDeviceImpl_GetParent,
6682 /*** Creation methods**/
6683 IWineD3DDeviceImpl_CreateVertexBuffer,
6684 IWineD3DDeviceImpl_CreateIndexBuffer,
6685 IWineD3DDeviceImpl_CreateStateBlock,
6686 IWineD3DDeviceImpl_CreateSurface,
6687 IWineD3DDeviceImpl_CreateTexture,
6688 IWineD3DDeviceImpl_CreateVolumeTexture,
6689 IWineD3DDeviceImpl_CreateVolume,
6690 IWineD3DDeviceImpl_CreateCubeTexture,
6691 IWineD3DDeviceImpl_CreateQuery,
6692 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6693 IWineD3DDeviceImpl_CreateVertexDeclaration,
6694 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6695 IWineD3DDeviceImpl_CreateVertexShader,
6696 IWineD3DDeviceImpl_CreatePixelShader,
6697 IWineD3DDeviceImpl_CreatePalette,
6698 /*** Odd functions **/
6699 IWineD3DDeviceImpl_Init3D,
6700 IWineD3DDeviceImpl_Uninit3D,
6701 IWineD3DDeviceImpl_SetFullscreen,
6702 IWineD3DDeviceImpl_SetMultithreaded,
6703 IWineD3DDeviceImpl_EvictManagedResources,
6704 IWineD3DDeviceImpl_GetAvailableTextureMem,
6705 IWineD3DDeviceImpl_GetBackBuffer,
6706 IWineD3DDeviceImpl_GetCreationParameters,
6707 IWineD3DDeviceImpl_GetDeviceCaps,
6708 IWineD3DDeviceImpl_GetDirect3D,
6709 IWineD3DDeviceImpl_GetDisplayMode,
6710 IWineD3DDeviceImpl_SetDisplayMode,
6711 IWineD3DDeviceImpl_GetHWND,
6712 IWineD3DDeviceImpl_SetHWND,
6713 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6714 IWineD3DDeviceImpl_GetRasterStatus,
6715 IWineD3DDeviceImpl_GetSwapChain,
6716 IWineD3DDeviceImpl_Reset,
6717 IWineD3DDeviceImpl_SetDialogBoxMode,
6718 IWineD3DDeviceImpl_SetCursorProperties,
6719 IWineD3DDeviceImpl_SetCursorPosition,
6720 IWineD3DDeviceImpl_ShowCursor,
6721 IWineD3DDeviceImpl_TestCooperativeLevel,
6722 /*** Getters and setters **/
6723 IWineD3DDeviceImpl_SetClipPlane,
6724 IWineD3DDeviceImpl_GetClipPlane,
6725 IWineD3DDeviceImpl_SetClipStatus,
6726 IWineD3DDeviceImpl_GetClipStatus,
6727 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6728 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6729 IWineD3DDeviceImpl_SetDepthStencilSurface,
6730 IWineD3DDeviceImpl_GetDepthStencilSurface,
6731 IWineD3DDeviceImpl_SetFVF,
6732 IWineD3DDeviceImpl_GetFVF,
6733 IWineD3DDeviceImpl_SetGammaRamp,
6734 IWineD3DDeviceImpl_GetGammaRamp,
6735 IWineD3DDeviceImpl_SetIndices,
6736 IWineD3DDeviceImpl_GetIndices,
6737 IWineD3DDeviceImpl_SetBaseVertexIndex,
6738 IWineD3DDeviceImpl_GetBaseVertexIndex,
6739 IWineD3DDeviceImpl_SetLight,
6740 IWineD3DDeviceImpl_GetLight,
6741 IWineD3DDeviceImpl_SetLightEnable,
6742 IWineD3DDeviceImpl_GetLightEnable,
6743 IWineD3DDeviceImpl_SetMaterial,
6744 IWineD3DDeviceImpl_GetMaterial,
6745 IWineD3DDeviceImpl_SetNPatchMode,
6746 IWineD3DDeviceImpl_GetNPatchMode,
6747 IWineD3DDeviceImpl_SetPaletteEntries,
6748 IWineD3DDeviceImpl_GetPaletteEntries,
6749 IWineD3DDeviceImpl_SetPixelShader,
6750 IWineD3DDeviceImpl_GetPixelShader,
6751 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6752 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6753 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6754 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6755 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6756 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6757 IWineD3DDeviceImpl_SetRenderState,
6758 IWineD3DDeviceImpl_GetRenderState,
6759 IWineD3DDeviceImpl_SetRenderTarget,
6760 IWineD3DDeviceImpl_GetRenderTarget,
6761 IWineD3DDeviceImpl_SetFrontBackBuffers,
6762 IWineD3DDeviceImpl_SetSamplerState,
6763 IWineD3DDeviceImpl_GetSamplerState,
6764 IWineD3DDeviceImpl_SetScissorRect,
6765 IWineD3DDeviceImpl_GetScissorRect,
6766 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6767 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6768 IWineD3DDeviceImpl_SetStreamSource,
6769 IWineD3DDeviceImpl_GetStreamSource,
6770 IWineD3DDeviceImpl_SetStreamSourceFreq,
6771 IWineD3DDeviceImpl_GetStreamSourceFreq,
6772 IWineD3DDeviceImpl_SetTexture,
6773 IWineD3DDeviceImpl_GetTexture,
6774 IWineD3DDeviceImpl_SetTextureStageState,
6775 IWineD3DDeviceImpl_GetTextureStageState,
6776 IWineD3DDeviceImpl_SetTransform,
6777 IWineD3DDeviceImpl_GetTransform,
6778 IWineD3DDeviceImpl_SetVertexDeclaration,
6779 IWineD3DDeviceImpl_GetVertexDeclaration,
6780 IWineD3DDeviceImpl_SetVertexShader,
6781 IWineD3DDeviceImpl_GetVertexShader,
6782 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6783 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6784 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6785 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6786 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6787 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6788 IWineD3DDeviceImpl_SetViewport,
6789 IWineD3DDeviceImpl_GetViewport,
6790 IWineD3DDeviceImpl_MultiplyTransform,
6791 IWineD3DDeviceImpl_ValidateDevice,
6792 IWineD3DDeviceImpl_ProcessVertices,
6793 /*** State block ***/
6794 IWineD3DDeviceImpl_BeginStateBlock,
6795 IWineD3DDeviceImpl_EndStateBlock,
6796 /*** Scene management ***/
6797 IWineD3DDeviceImpl_BeginScene,
6798 IWineD3DDeviceImpl_EndScene,
6799 IWineD3DDeviceImpl_Present,
6800 IWineD3DDeviceImpl_Clear,
6801 /*** Drawing ***/
6802 IWineD3DDeviceImpl_DrawPrimitive,
6803 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6804 IWineD3DDeviceImpl_DrawPrimitiveUP,
6805 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6806 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6807 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6808 IWineD3DDeviceImpl_DrawRectPatch,
6809 IWineD3DDeviceImpl_DrawTriPatch,
6810 IWineD3DDeviceImpl_DeletePatch,
6811 IWineD3DDeviceImpl_ColorFill,
6812 IWineD3DDeviceImpl_UpdateTexture,
6813 IWineD3DDeviceImpl_UpdateSurface,
6814 IWineD3DDeviceImpl_GetFrontBufferData,
6815 /*** object tracking ***/
6816 IWineD3DDeviceImpl_ResourceReleased
6820 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6821 WINED3DRS_ALPHABLENDENABLE ,
6822 WINED3DRS_ALPHAFUNC ,
6823 WINED3DRS_ALPHAREF ,
6824 WINED3DRS_ALPHATESTENABLE ,
6825 WINED3DRS_BLENDOP ,
6826 WINED3DRS_COLORWRITEENABLE ,
6827 WINED3DRS_DESTBLEND ,
6828 WINED3DRS_DITHERENABLE ,
6829 WINED3DRS_FILLMODE ,
6830 WINED3DRS_FOGDENSITY ,
6831 WINED3DRS_FOGEND ,
6832 WINED3DRS_FOGSTART ,
6833 WINED3DRS_LASTPIXEL ,
6834 WINED3DRS_SHADEMODE ,
6835 WINED3DRS_SRCBLEND ,
6836 WINED3DRS_STENCILENABLE ,
6837 WINED3DRS_STENCILFAIL ,
6838 WINED3DRS_STENCILFUNC ,
6839 WINED3DRS_STENCILMASK ,
6840 WINED3DRS_STENCILPASS ,
6841 WINED3DRS_STENCILREF ,
6842 WINED3DRS_STENCILWRITEMASK ,
6843 WINED3DRS_STENCILZFAIL ,
6844 WINED3DRS_TEXTUREFACTOR ,
6845 WINED3DRS_WRAP0 ,
6846 WINED3DRS_WRAP1 ,
6847 WINED3DRS_WRAP2 ,
6848 WINED3DRS_WRAP3 ,
6849 WINED3DRS_WRAP4 ,
6850 WINED3DRS_WRAP5 ,
6851 WINED3DRS_WRAP6 ,
6852 WINED3DRS_WRAP7 ,
6853 WINED3DRS_ZENABLE ,
6854 WINED3DRS_ZFUNC ,
6855 WINED3DRS_ZWRITEENABLE
6858 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6859 WINED3DTSS_ADDRESSW ,
6860 WINED3DTSS_ALPHAARG0 ,
6861 WINED3DTSS_ALPHAARG1 ,
6862 WINED3DTSS_ALPHAARG2 ,
6863 WINED3DTSS_ALPHAOP ,
6864 WINED3DTSS_BUMPENVLOFFSET ,
6865 WINED3DTSS_BUMPENVLSCALE ,
6866 WINED3DTSS_BUMPENVMAT00 ,
6867 WINED3DTSS_BUMPENVMAT01 ,
6868 WINED3DTSS_BUMPENVMAT10 ,
6869 WINED3DTSS_BUMPENVMAT11 ,
6870 WINED3DTSS_COLORARG0 ,
6871 WINED3DTSS_COLORARG1 ,
6872 WINED3DTSS_COLORARG2 ,
6873 WINED3DTSS_COLOROP ,
6874 WINED3DTSS_RESULTARG ,
6875 WINED3DTSS_TEXCOORDINDEX ,
6876 WINED3DTSS_TEXTURETRANSFORMFLAGS
6879 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6880 WINED3DSAMP_ADDRESSU ,
6881 WINED3DSAMP_ADDRESSV ,
6882 WINED3DSAMP_ADDRESSW ,
6883 WINED3DSAMP_BORDERCOLOR ,
6884 WINED3DSAMP_MAGFILTER ,
6885 WINED3DSAMP_MINFILTER ,
6886 WINED3DSAMP_MIPFILTER ,
6887 WINED3DSAMP_MIPMAPLODBIAS ,
6888 WINED3DSAMP_MAXMIPLEVEL ,
6889 WINED3DSAMP_MAXANISOTROPY ,
6890 WINED3DSAMP_SRGBTEXTURE ,
6891 WINED3DSAMP_ELEMENTINDEX
6894 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6895 WINED3DRS_AMBIENT ,
6896 WINED3DRS_AMBIENTMATERIALSOURCE ,
6897 WINED3DRS_CLIPPING ,
6898 WINED3DRS_CLIPPLANEENABLE ,
6899 WINED3DRS_COLORVERTEX ,
6900 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6901 WINED3DRS_EMISSIVEMATERIALSOURCE ,
6902 WINED3DRS_FOGDENSITY ,
6903 WINED3DRS_FOGEND ,
6904 WINED3DRS_FOGSTART ,
6905 WINED3DRS_FOGTABLEMODE ,
6906 WINED3DRS_FOGVERTEXMODE ,
6907 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
6908 WINED3DRS_LIGHTING ,
6909 WINED3DRS_LOCALVIEWER ,
6910 WINED3DRS_MULTISAMPLEANTIALIAS ,
6911 WINED3DRS_MULTISAMPLEMASK ,
6912 WINED3DRS_NORMALIZENORMALS ,
6913 WINED3DRS_PATCHEDGESTYLE ,
6914 WINED3DRS_POINTSCALE_A ,
6915 WINED3DRS_POINTSCALE_B ,
6916 WINED3DRS_POINTSCALE_C ,
6917 WINED3DRS_POINTSCALEENABLE ,
6918 WINED3DRS_POINTSIZE ,
6919 WINED3DRS_POINTSIZE_MAX ,
6920 WINED3DRS_POINTSIZE_MIN ,
6921 WINED3DRS_POINTSPRITEENABLE ,
6922 WINED3DRS_RANGEFOGENABLE ,
6923 WINED3DRS_SPECULARMATERIALSOURCE ,
6924 WINED3DRS_TWEENFACTOR ,
6925 WINED3DRS_VERTEXBLEND
6928 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
6929 WINED3DTSS_TEXCOORDINDEX ,
6930 WINED3DTSS_TEXTURETRANSFORMFLAGS
6933 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
6934 WINED3DSAMP_DMAPOFFSET
6937 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
6938 DWORD rep = StateTable[state].representative;
6939 DWORD idx;
6940 BYTE shift;
6941 UINT i;
6942 WineD3DContext *context;
6944 if(!rep) return;
6945 for(i = 0; i < This->numContexts; i++) {
6946 context = This->contexts[i];
6947 if(isStateDirty(context, rep)) continue;
6949 context->dirtyArray[context->numDirtyEntries++] = rep;
6950 idx = rep >> 5;
6951 shift = rep & 0x1f;
6952 context->isStateDirty[idx] |= (1 << shift);