push b72af2511d67bded8ece08d825ff0eb4a60c20a6
[wine/hacks.git] / dlls / wined3d / device.c
blob4c2b39632561d16b5ed2abecee18d82a6a38f5d7
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 for(i = 0; i < MAX_STREAMS; i++) {
518 if(object->streamSource[i]) {
519 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
522 if(object->pIndexData) {
523 IWineD3DIndexBuffer_AddRef(object->pIndexData);
525 if(object->vertexShader) {
526 IWineD3DVertexShader_AddRef(object->vertexShader);
528 if(object->pixelShader) {
529 IWineD3DPixelShader_AddRef(object->pixelShader);
532 } else if (Type == WINED3DSBT_PIXELSTATE) {
534 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
535 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
537 object->changed.pixelShader = TRUE;
539 /* Pixel Shader Constants */
540 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
541 object->contained_ps_consts_f[i] = i;
542 object->changed.pixelShaderConstantsF[i] = TRUE;
544 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
545 for (i = 0; i < MAX_CONST_B; ++i) {
546 object->contained_ps_consts_b[i] = i;
547 object->changed.pixelShaderConstantsB[i] = TRUE;
549 object->num_contained_ps_consts_b = MAX_CONST_B;
550 for (i = 0; i < MAX_CONST_I; ++i) {
551 object->contained_ps_consts_i[i] = i;
552 object->changed.pixelShaderConstantsI[i] = TRUE;
554 object->num_contained_ps_consts_i = MAX_CONST_I;
556 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
557 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
558 object->contained_render_states[i] = SavedPixelStates_R[i];
560 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
561 for (j = 0; j < MAX_TEXTURES; j++) {
562 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
563 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
564 object->contained_tss_states[object->num_contained_tss_states].stage = j;
565 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
566 object->num_contained_tss_states++;
569 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
570 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
571 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
572 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
573 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
574 object->num_contained_sampler_states++;
577 if(object->pixelShader) {
578 IWineD3DPixelShader_AddRef(object->pixelShader);
581 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
582 * on them. This makes releasing the buffer easier
584 for(i = 0; i < MAX_STREAMS; i++) {
585 object->streamSource[i] = NULL;
587 object->pIndexData = NULL;
588 object->vertexShader = NULL;
590 } else if (Type == WINED3DSBT_VERTEXSTATE) {
592 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
593 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
595 object->changed.vertexShader = TRUE;
597 /* Vertex Shader Constants */
598 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
599 object->changed.vertexShaderConstantsF[i] = TRUE;
600 object->contained_vs_consts_f[i] = i;
602 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
603 for (i = 0; i < MAX_CONST_B; ++i) {
604 object->changed.vertexShaderConstantsB[i] = TRUE;
605 object->contained_vs_consts_b[i] = i;
607 object->num_contained_vs_consts_b = MAX_CONST_B;
608 for (i = 0; i < MAX_CONST_I; ++i) {
609 object->changed.vertexShaderConstantsI[i] = TRUE;
610 object->contained_vs_consts_i[i] = i;
612 object->num_contained_vs_consts_i = MAX_CONST_I;
613 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
614 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
615 object->contained_render_states[i] = SavedVertexStates_R[i];
617 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
618 for (j = 0; j < MAX_TEXTURES; j++) {
619 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
620 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
621 object->contained_tss_states[object->num_contained_tss_states].stage = j;
622 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
623 object->num_contained_tss_states++;
626 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
627 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
628 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
629 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
630 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
631 object->num_contained_sampler_states++;
635 for(j = 0; j < LIGHTMAP_SIZE; j++) {
636 struct list *e;
637 LIST_FOR_EACH(e, &object->lightMap[j]) {
638 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
639 light->changed = TRUE;
640 light->enabledChanged = TRUE;
644 for(i = 0; i < MAX_STREAMS; i++) {
645 if(object->streamSource[i]) {
646 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
649 if(object->vertexShader) {
650 IWineD3DVertexShader_AddRef(object->vertexShader);
652 object->pIndexData = NULL;
653 object->pixelShader = NULL;
654 } else {
655 FIXME("Unrecognized state block type %d\n", Type);
658 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
659 return WINED3D_OK;
662 /* ************************************
663 MSDN:
664 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
666 Discard
667 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
669 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.
671 ******************************** */
673 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) {
674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
675 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
676 unsigned int Size = 1;
677 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
678 TRACE("(%p) Create surface\n",This);
680 /** FIXME: Check ranges on the inputs are valid
681 * MSDN
682 * MultisampleQuality
683 * [in] Quality level. The valid range is between zero and one less than the level
684 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
685 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
686 * values of paired render targets, depth stencil surfaces, and the MultiSample type
687 * must all match.
688 *******************************/
692 * TODO: Discard MSDN
693 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
695 * If this flag is set, the contents of the depth stencil buffer will be
696 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
697 * with a different depth surface.
699 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
700 ***************************/
702 if(MultisampleQuality < 0) {
703 FIXME("Invalid multisample level %d\n", MultisampleQuality);
704 return WINED3DERR_INVALIDCALL; /* TODO: Check that this is the case! */
707 if(MultisampleQuality > 0) {
708 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
709 MultisampleQuality=0;
712 /** FIXME: Check that the format is supported
713 * by the device.
714 *******************************/
716 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
717 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
718 * space!
719 *********************************/
720 if (WINED3DFMT_UNKNOWN == Format) {
721 Size = 0;
722 } else if (Format == WINED3DFMT_DXT1) {
723 /* DXT1 is half byte per pixel */
724 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
726 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
727 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
728 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
729 } else {
730 /* The pitch is a multiple of 4 bytes */
731 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
732 Size *= Height;
735 /** Create and initialise the surface resource **/
736 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
737 /* "Standalone" surface */
738 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
740 object->currentDesc.Width = Width;
741 object->currentDesc.Height = Height;
742 object->currentDesc.MultiSampleType = MultiSample;
743 object->currentDesc.MultiSampleQuality = MultisampleQuality;
744 object->glDescription.level = Level;
746 /* Flags */
747 object->Flags = 0;
748 object->Flags |= Discard ? SFLAG_DISCARD : 0;
749 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
750 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
753 if (WINED3DFMT_UNKNOWN != Format) {
754 object->bytesPerPixel = tableEntry->bpp;
755 } else {
756 object->bytesPerPixel = 0;
759 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
761 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
763 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
764 * this function is too deep to need to care about things like this.
765 * Levels need to be checked too, and possibly Type since they all affect what can be done.
766 * ****************************************/
767 switch(Pool) {
768 case WINED3DPOOL_SCRATCH:
769 if(!Lockable)
770 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
771 "which are mutually exclusive, setting lockable to TRUE\n");
772 Lockable = TRUE;
773 break;
774 case WINED3DPOOL_SYSTEMMEM:
775 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
776 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
777 case WINED3DPOOL_MANAGED:
778 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
779 "Usage of DYNAMIC which are mutually exclusive, not doing "
780 "anything just telling you.\n");
781 break;
782 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
783 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
784 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
785 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
786 break;
787 default:
788 FIXME("(%p) Unknown pool %d\n", This, Pool);
789 break;
792 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
793 FIXME("Trying to create a render target that isn't in the default pool\n");
796 /* mark the texture as dirty so that it gets loaded first time around*/
797 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
798 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
799 This, Width, Height, Format, debug_d3dformat(Format),
800 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
802 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
803 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
804 This->ddraw_primary = (IWineD3DSurface *) object;
806 /* Look at the implementation and set the correct Vtable */
807 switch(Impl) {
808 case SURFACE_OPENGL:
809 /* Check if a 3D adapter is available when creating gl surfaces */
810 if(!This->adapter) {
811 ERR("OpenGL surfaces are not available without opengl\n");
812 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
813 HeapFree(GetProcessHeap(), 0, object);
814 return WINED3DERR_NOTAVAILABLE;
816 break;
818 case SURFACE_GDI:
819 object->lpVtbl = &IWineGDISurface_Vtbl;
820 break;
822 default:
823 /* To be sure to catch this */
824 ERR("Unknown requested surface implementation %d!\n", Impl);
825 IWineD3DSurface_Release((IWineD3DSurface *) object);
826 return WINED3DERR_INVALIDCALL;
829 list_init(&object->renderbuffers);
831 /* Call the private setup routine */
832 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
836 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
837 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
838 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
839 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
842 IWineD3DTextureImpl *object;
843 unsigned int i;
844 UINT tmpW;
845 UINT tmpH;
846 HRESULT hr;
847 unsigned int pow2Width;
848 unsigned int pow2Height;
851 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
852 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
853 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
855 /* TODO: It should only be possible to create textures for formats
856 that are reported as supported */
857 if (WINED3DFMT_UNKNOWN >= Format) {
858 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
859 return WINED3DERR_INVALIDCALL;
862 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
863 D3DINITIALIZEBASETEXTURE(object->baseTexture);
864 object->width = Width;
865 object->height = Height;
867 /** Non-power2 support **/
868 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
869 pow2Width = Width;
870 pow2Height = Height;
871 } else {
872 /* Find the nearest pow2 match */
873 pow2Width = pow2Height = 1;
874 while (pow2Width < Width) pow2Width <<= 1;
875 while (pow2Height < Height) pow2Height <<= 1;
878 /** FIXME: add support for real non-power-two if it's provided by the video card **/
879 /* Precalculated scaling for 'faked' non power of two texture coords */
880 object->pow2scalingFactorX = (((float)Width) / ((float)pow2Width));
881 object->pow2scalingFactorY = (((float)Height) / ((float)pow2Height));
882 TRACE(" xf(%f) yf(%f)\n", object->pow2scalingFactorX, object->pow2scalingFactorY);
884 /* Calculate levels for mip mapping */
885 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
886 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
887 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
888 return WINED3DERR_INVALIDCALL;
890 if(Levels > 1) {
891 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
892 return WINED3DERR_INVALIDCALL;
894 object->baseTexture.levels = 1;
895 } else if (Levels == 0) {
896 TRACE("calculating levels %d\n", object->baseTexture.levels);
897 object->baseTexture.levels++;
898 tmpW = Width;
899 tmpH = Height;
900 while (tmpW > 1 || tmpH > 1) {
901 tmpW = max(1, tmpW >> 1);
902 tmpH = max(1, tmpH >> 1);
903 object->baseTexture.levels++;
905 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
908 /* Generate all the surfaces */
909 tmpW = Width;
910 tmpH = Height;
911 for (i = 0; i < object->baseTexture.levels; i++)
913 /* use the callback to create the texture surface */
914 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
915 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
916 FIXME("Failed to create surface %p\n", object);
917 /* clean up */
918 object->surfaces[i] = NULL;
919 IWineD3DTexture_Release((IWineD3DTexture *)object);
921 *ppTexture = NULL;
922 return hr;
925 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
926 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
927 /* calculate the next mipmap level */
928 tmpW = max(1, tmpW >> 1);
929 tmpH = max(1, tmpH >> 1);
932 TRACE("(%p) : Created texture %p\n", This, object);
933 return WINED3D_OK;
936 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
937 UINT Width, UINT Height, UINT Depth,
938 UINT Levels, DWORD Usage,
939 WINED3DFORMAT Format, WINED3DPOOL Pool,
940 IWineD3DVolumeTexture **ppVolumeTexture,
941 HANDLE *pSharedHandle, IUnknown *parent,
942 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
945 IWineD3DVolumeTextureImpl *object;
946 unsigned int i;
947 UINT tmpW;
948 UINT tmpH;
949 UINT tmpD;
951 /* TODO: It should only be possible to create textures for formats
952 that are reported as supported */
953 if (WINED3DFMT_UNKNOWN >= Format) {
954 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
955 return WINED3DERR_INVALIDCALL;
958 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
959 D3DINITIALIZEBASETEXTURE(object->baseTexture);
961 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
962 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
964 object->width = Width;
965 object->height = Height;
966 object->depth = Depth;
968 /* Calculate levels for mip mapping */
969 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
970 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
971 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
972 return WINED3DERR_INVALIDCALL;
974 if(Levels > 1) {
975 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
976 return WINED3DERR_INVALIDCALL;
978 Levels = 1;
979 } else if (Levels == 0) {
980 object->baseTexture.levels++;
981 tmpW = Width;
982 tmpH = Height;
983 tmpD = Depth;
984 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
985 tmpW = max(1, tmpW >> 1);
986 tmpH = max(1, tmpH >> 1);
987 tmpD = max(1, tmpD >> 1);
988 object->baseTexture.levels++;
990 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
993 /* Generate all the surfaces */
994 tmpW = Width;
995 tmpH = Height;
996 tmpD = Depth;
998 for (i = 0; i < object->baseTexture.levels; i++)
1000 HRESULT hr;
1001 /* Create the volume */
1002 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
1003 (IWineD3DVolume **)&object->volumes[i], pSharedHandle);
1005 if(FAILED(hr)) {
1006 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
1007 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
1008 *ppVolumeTexture = NULL;
1009 return hr;
1012 /* Set its container to this object */
1013 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1015 /* calcualte the next mipmap level */
1016 tmpW = max(1, tmpW >> 1);
1017 tmpH = max(1, tmpH >> 1);
1018 tmpD = max(1, tmpD >> 1);
1021 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1022 TRACE("(%p) : Created volume texture %p\n", This, object);
1023 return WINED3D_OK;
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1027 UINT Width, UINT Height, UINT Depth,
1028 DWORD Usage,
1029 WINED3DFORMAT Format, WINED3DPOOL Pool,
1030 IWineD3DVolume** ppVolume,
1031 HANDLE* pSharedHandle, IUnknown *parent) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1035 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1037 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1039 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1040 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1042 object->currentDesc.Width = Width;
1043 object->currentDesc.Height = Height;
1044 object->currentDesc.Depth = Depth;
1045 object->bytesPerPixel = formatDesc->bpp;
1047 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1048 object->lockable = TRUE;
1049 object->locked = FALSE;
1050 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1051 object->dirty = TRUE;
1053 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1056 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1057 UINT Levels, DWORD Usage,
1058 WINED3DFORMAT Format, WINED3DPOOL Pool,
1059 IWineD3DCubeTexture **ppCubeTexture,
1060 HANDLE *pSharedHandle, IUnknown *parent,
1061 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1064 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1065 unsigned int i, j;
1066 UINT tmpW;
1067 HRESULT hr;
1068 unsigned int pow2EdgeLength = EdgeLength;
1070 /* TODO: It should only be possible to create textures for formats
1071 that are reported as supported */
1072 if (WINED3DFMT_UNKNOWN >= Format) {
1073 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1074 return WINED3DERR_INVALIDCALL;
1077 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1078 WARN("(%p) : Tried to create not supported cube texture\n", This);
1079 return WINED3DERR_INVALIDCALL;
1082 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1083 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1085 TRACE("(%p) Create Cube Texture\n", This);
1087 /** Non-power2 support **/
1089 /* Find the nearest pow2 match */
1090 pow2EdgeLength = 1;
1091 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1093 object->edgeLength = EdgeLength;
1094 /* TODO: support for native non-power 2 */
1095 /* Precalculated scaling for 'faked' non power of two texture coords */
1096 object->pow2scalingFactor = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 /* Calculate levels for mip mapping */
1099 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1100 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1101 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1102 return WINED3DERR_INVALIDCALL;
1104 if(Levels > 1) {
1105 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1106 return WINED3DERR_INVALIDCALL;
1108 Levels = 1;
1109 } else if (Levels == 0) {
1110 object->baseTexture.levels++;
1111 tmpW = EdgeLength;
1112 while (tmpW > 1) {
1113 tmpW = max(1, tmpW >> 1);
1114 object->baseTexture.levels++;
1116 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1119 /* Generate all the surfaces */
1120 tmpW = EdgeLength;
1121 for (i = 0; i < object->baseTexture.levels; i++) {
1123 /* Create the 6 faces */
1124 for (j = 0; j < 6; j++) {
1126 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1127 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1129 if(hr!= WINED3D_OK) {
1130 /* clean up */
1131 int k;
1132 int l;
1133 for (l = 0; l < j; l++) {
1134 IWineD3DSurface_Release(object->surfaces[j][i]);
1136 for (k = 0; k < i; k++) {
1137 for (l = 0; l < 6; l++) {
1138 IWineD3DSurface_Release(object->surfaces[l][j]);
1142 FIXME("(%p) Failed to create surface\n",object);
1143 HeapFree(GetProcessHeap(),0,object);
1144 *ppCubeTexture = NULL;
1145 return hr;
1147 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1148 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1150 tmpW = max(1, tmpW >> 1);
1153 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1154 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1155 return WINED3D_OK;
1158 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1160 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1161 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1163 /* Just a check to see if we support this type of query */
1164 switch(Type) {
1165 case WINED3DQUERYTYPE_OCCLUSION:
1166 TRACE("(%p) occlusion query\n", This);
1167 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1168 hr = WINED3D_OK;
1169 else
1170 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1171 break;
1173 case WINED3DQUERYTYPE_EVENT:
1174 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1175 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1176 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1178 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1180 hr = WINED3D_OK;
1181 break;
1183 case WINED3DQUERYTYPE_VCACHE:
1184 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1185 case WINED3DQUERYTYPE_VERTEXSTATS:
1186 case WINED3DQUERYTYPE_TIMESTAMP:
1187 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1188 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1189 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1190 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1191 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1192 case WINED3DQUERYTYPE_PIXELTIMINGS:
1193 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1194 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1195 default:
1196 FIXME("(%p) Unhandled query type %d\n", This, Type);
1198 if(NULL == ppQuery || hr != WINED3D_OK) {
1199 return hr;
1202 D3DCREATEOBJECTINSTANCE(object, Query)
1203 object->type = Type;
1204 /* allocated the 'extended' data based on the type of query requested */
1205 switch(Type){
1206 case WINED3DQUERYTYPE_OCCLUSION:
1207 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1208 TRACE("(%p) Allocating data for an occlusion query\n", This);
1209 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1210 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1211 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1212 break;
1214 case WINED3DQUERYTYPE_EVENT:
1215 if(GL_SUPPORT(APPLE_FENCE)) {
1216 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1217 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1218 checkGLcall("glGenFencesAPPLE");
1219 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1220 } else if(GL_SUPPORT(NV_FENCE)) {
1221 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1222 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1223 checkGLcall("glGenFencesNV");
1224 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1226 break;
1228 case WINED3DQUERYTYPE_VCACHE:
1229 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1230 case WINED3DQUERYTYPE_VERTEXSTATS:
1231 case WINED3DQUERYTYPE_TIMESTAMP:
1232 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1233 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1234 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1235 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1236 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1237 case WINED3DQUERYTYPE_PIXELTIMINGS:
1238 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1239 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1240 default:
1241 object->extendedData = 0;
1242 FIXME("(%p) Unhandled query type %d\n",This , Type);
1244 TRACE("(%p) : Created Query %p\n", This, object);
1245 return WINED3D_OK;
1248 /*****************************************************************************
1249 * IWineD3DDeviceImpl_SetupFullscreenWindow
1251 * Helper function that modifies a HWND's Style and ExStyle for proper
1252 * fullscreen use.
1254 * Params:
1255 * iface: Pointer to the IWineD3DDevice interface
1256 * window: Window to setup
1258 *****************************************************************************/
1259 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1262 LONG style, exStyle;
1263 /* Don't do anything if an original style is stored.
1264 * That shouldn't happen
1266 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1267 if (This->style || This->exStyle) {
1268 ERR("(%p): Want to change the window parameters of HWND %p, but "
1269 "another style is stored for restoration afterwards\n", This, window);
1272 /* Get the parameters and save them */
1273 style = GetWindowLongW(window, GWL_STYLE);
1274 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1275 This->style = style;
1276 This->exStyle = exStyle;
1278 /* Filter out window decorations */
1279 style &= ~WS_CAPTION;
1280 style &= ~WS_THICKFRAME;
1281 exStyle &= ~WS_EX_WINDOWEDGE;
1282 exStyle &= ~WS_EX_CLIENTEDGE;
1284 /* Make sure the window is managed, otherwise we won't get keyboard input */
1285 style |= WS_POPUP | WS_SYSMENU;
1287 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1288 This->style, This->exStyle, style, exStyle);
1290 SetWindowLongW(window, GWL_STYLE, style);
1291 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1293 /* Inform the window about the update. */
1294 SetWindowPos(window, HWND_TOP, 0, 0,
1295 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1296 ShowWindow(window, SW_NORMAL);
1299 /*****************************************************************************
1300 * IWineD3DDeviceImpl_RestoreWindow
1302 * Helper function that restores a windows' properties when taking it out
1303 * of fullscreen mode
1305 * Params:
1306 * iface: Pointer to the IWineD3DDevice interface
1307 * window: Window to setup
1309 *****************************************************************************/
1310 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1313 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1314 * switch, do nothing
1316 if (!This->style && !This->exStyle) return;
1318 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1319 This, window, This->style, This->exStyle);
1321 SetWindowLongW(window, GWL_STYLE, This->style);
1322 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1324 /* Delete the old values */
1325 This->style = 0;
1326 This->exStyle = 0;
1328 /* Inform the window about the update */
1329 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1330 0, 0, 0, 0, /* Pos, Size, ignored */
1331 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1334 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1335 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1336 IUnknown* parent,
1337 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1338 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1341 HDC hDc;
1342 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1343 HRESULT hr = WINED3D_OK;
1344 IUnknown *bufferParent;
1346 TRACE("(%p) : Created Aditional Swap Chain\n", This);
1348 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1349 * does a device hold a reference to a swap chain giving them a lifetime of the device
1350 * or does the swap chain notify the device of its destruction.
1351 *******************************/
1353 /* Check the params */
1354 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1355 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1356 return WINED3DERR_INVALIDCALL;
1357 } else if (pPresentationParameters->BackBufferCount > 1) {
1358 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");
1361 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1363 /*********************
1364 * Lookup the window Handle and the relating X window handle
1365 ********************/
1367 /* Setup hwnd we are using, plus which display this equates to */
1368 object->win_handle = pPresentationParameters->hDeviceWindow;
1369 if (!object->win_handle) {
1370 object->win_handle = This->createParms.hFocusWindow;
1373 object->win_handle = GetAncestor(object->win_handle, GA_ROOT);
1374 hDc = GetDC(object->win_handle);
1375 TRACE("Using hDc %p\n", hDc);
1377 if (NULL == hDc) {
1378 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1379 return WINED3DERR_NOTAVAILABLE;
1382 object->orig_width = GetSystemMetrics(SM_CXSCREEN);
1383 object->orig_height = GetSystemMetrics(SM_CYSCREEN);
1384 object->orig_fmt = pixelformat_for_depth(GetDeviceCaps(hDc, BITSPIXEL) * GetDeviceCaps(hDc, PLANES));
1385 ReleaseDC(object->win_handle, hDc);
1387 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1388 * then the corresponding dimension of the client area of the hDeviceWindow
1389 * (or the focus window, if hDeviceWindow is NULL) is taken.
1390 **********************/
1392 if (pPresentationParameters->Windowed &&
1393 ((pPresentationParameters->BackBufferWidth == 0) ||
1394 (pPresentationParameters->BackBufferHeight == 0) ||
1395 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1397 RECT Rect;
1398 GetClientRect(object->win_handle, &Rect);
1400 if (pPresentationParameters->BackBufferWidth == 0) {
1401 pPresentationParameters->BackBufferWidth = Rect.right;
1402 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1404 if (pPresentationParameters->BackBufferHeight == 0) {
1405 pPresentationParameters->BackBufferHeight = Rect.bottom;
1406 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1408 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1409 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1410 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1414 /* Put the correct figures in the presentation parameters */
1415 TRACE("Copying across presentation parameters\n");
1416 object->presentParms = *pPresentationParameters;
1418 TRACE("calling rendertarget CB\n");
1419 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1420 parent,
1421 object->presentParms.BackBufferWidth,
1422 object->presentParms.BackBufferHeight,
1423 object->presentParms.BackBufferFormat,
1424 object->presentParms.MultiSampleType,
1425 object->presentParms.MultiSampleQuality,
1426 TRUE /* Lockable */,
1427 &object->frontBuffer,
1428 NULL /* pShared (always null)*/);
1429 if (object->frontBuffer != NULL) {
1430 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1431 } else {
1432 ERR("Failed to create the front buffer\n");
1433 goto error;
1437 * Create an opengl context for the display visual
1438 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1439 * use different properties after that point in time. FIXME: How to handle when requested format
1440 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1441 * it chooses is identical to the one already being used!
1442 **********************************/
1443 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1445 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1446 if(!object->context)
1447 return E_OUTOFMEMORY;
1448 object->num_contexts = 1;
1450 ENTER_GL();
1451 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1452 LEAVE_GL();
1454 if (!object->context[0]) {
1455 ERR("Failed to create a new context\n");
1456 hr = WINED3DERR_NOTAVAILABLE;
1457 goto error;
1458 } else {
1459 TRACE("Context created (HWND=%p, glContext=%p)\n",
1460 object->win_handle, object->context[0]->glCtx);
1463 /*********************
1464 * Windowed / Fullscreen
1465 *******************/
1468 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1469 * so we should really check to see if there is a fullscreen swapchain already
1470 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1471 **************************************/
1473 if (!pPresentationParameters->Windowed) {
1475 DEVMODEW devmode;
1476 HDC hdc;
1477 int bpp = 0;
1478 RECT clip_rc;
1480 /* Get info on the current display setup */
1481 hdc = GetDC(0);
1482 bpp = GetDeviceCaps(hdc, BITSPIXEL);
1483 ReleaseDC(0, hdc);
1485 /* Change the display settings */
1486 memset(&devmode, 0, sizeof(devmode));
1487 devmode.dmSize = sizeof(devmode);
1488 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1489 devmode.dmBitsPerPel = (bpp >= 24) ? 32 : bpp; /* Stupid XVidMode cannot change bpp */
1490 devmode.dmPelsWidth = pPresentationParameters->BackBufferWidth;
1491 devmode.dmPelsHeight = pPresentationParameters->BackBufferHeight;
1492 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1494 /* For GetDisplayMode */
1495 This->ddraw_width = devmode.dmPelsWidth;
1496 This->ddraw_height = devmode.dmPelsHeight;
1497 This->ddraw_format = pPresentationParameters->BackBufferFormat;
1499 IWineD3DDevice_SetFullscreen(iface, TRUE);
1501 /* And finally clip mouse to our screen */
1502 SetRect(&clip_rc, 0, 0, devmode.dmPelsWidth, devmode.dmPelsHeight);
1503 ClipCursor(&clip_rc);
1506 /*********************
1507 * Create the back, front and stencil buffers
1508 *******************/
1509 if(object->presentParms.BackBufferCount > 0) {
1510 int i;
1512 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1513 if(!object->backBuffer) {
1514 ERR("Out of memory\n");
1515 hr = E_OUTOFMEMORY;
1516 goto error;
1519 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1520 TRACE("calling rendertarget CB\n");
1521 hr = D3DCB_CreateRenderTarget((IUnknown *) This->parent,
1522 parent,
1523 object->presentParms.BackBufferWidth,
1524 object->presentParms.BackBufferHeight,
1525 object->presentParms.BackBufferFormat,
1526 object->presentParms.MultiSampleType,
1527 object->presentParms.MultiSampleQuality,
1528 TRUE /* Lockable */,
1529 &object->backBuffer[i],
1530 NULL /* pShared (always null)*/);
1531 if(hr == WINED3D_OK && object->backBuffer[i]) {
1532 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1533 } else {
1534 ERR("Cannot create new back buffer\n");
1535 goto error;
1537 ENTER_GL();
1538 glDrawBuffer(GL_BACK);
1539 checkGLcall("glDrawBuffer(GL_BACK)");
1540 LEAVE_GL();
1542 } else {
1543 object->backBuffer = NULL;
1545 /* Single buffering - draw to front buffer */
1546 ENTER_GL();
1547 glDrawBuffer(GL_FRONT);
1548 checkGLcall("glDrawBuffer(GL_FRONT)");
1549 LEAVE_GL();
1552 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1553 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1554 TRACE("Creating depth stencil buffer\n");
1555 if (This->depthStencilBuffer == NULL ) {
1556 hr = D3DCB_CreateDepthStencil((IUnknown *) This->parent,
1557 parent,
1558 object->presentParms.BackBufferWidth,
1559 object->presentParms.BackBufferHeight,
1560 object->presentParms.AutoDepthStencilFormat,
1561 object->presentParms.MultiSampleType,
1562 object->presentParms.MultiSampleQuality,
1563 FALSE /* FIXME: Discard */,
1564 &This->depthStencilBuffer,
1565 NULL /* pShared (always null)*/ );
1566 if (This->depthStencilBuffer != NULL)
1567 IWineD3DSurface_SetContainer(This->depthStencilBuffer, 0);
1570 /** TODO: A check on width, height and multisample types
1571 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1572 ****************************/
1573 object->wantsDepthStencilBuffer = TRUE;
1574 } else {
1575 object->wantsDepthStencilBuffer = FALSE;
1578 TRACE("Created swapchain %p\n", object);
1579 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1580 return WINED3D_OK;
1582 error:
1583 if (object->backBuffer) {
1584 int i;
1585 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1586 if(object->backBuffer[i]) {
1587 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1588 IUnknown_Release(bufferParent); /* once for the get parent */
1589 if (IUnknown_Release(bufferParent) > 0) {
1590 FIXME("(%p) Something's still holding the back buffer\n",This);
1594 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1595 object->backBuffer = NULL;
1597 if(object->context[0])
1598 DestroyContext(This, object->context[0]);
1599 if(object->frontBuffer) {
1600 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1601 IUnknown_Release(bufferParent); /* once for the get parent */
1602 if (IUnknown_Release(bufferParent) > 0) {
1603 FIXME("(%p) Something's still holding the front buffer\n",This);
1606 HeapFree(GetProcessHeap(), 0, object);
1607 return hr;
1610 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1611 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1613 TRACE("(%p)\n", This);
1615 return This->NumberOfSwapChains;
1618 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1619 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1620 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1622 if(iSwapChain < This->NumberOfSwapChains) {
1623 *pSwapChain = This->swapchains[iSwapChain];
1624 IWineD3DSwapChain_AddRef(*pSwapChain);
1625 TRACE("(%p) returning %p\n", This, *pSwapChain);
1626 return WINED3D_OK;
1627 } else {
1628 TRACE("Swapchain out of range\n");
1629 *pSwapChain = NULL;
1630 return WINED3DERR_INVALIDCALL;
1634 /*****
1635 * Vertex Declaration
1636 *****/
1637 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1638 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, size_t element_count) {
1639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1640 IWineD3DVertexDeclarationImpl *object = NULL;
1641 HRESULT hr = WINED3D_OK;
1643 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1644 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1646 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1648 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1650 return hr;
1653 static size_t ConvertFvfToDeclaration(DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1655 unsigned int idx, idx2;
1656 unsigned int offset;
1657 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1658 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1659 BOOL has_blend_idx = has_blend &&
1660 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1661 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1662 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1663 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1664 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1665 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1666 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1668 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1669 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1671 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1672 WINED3DVERTEXELEMENT *elements = NULL;
1674 unsigned int size;
1675 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1676 if (has_blend_idx) num_blends--;
1678 /* Compute declaration size */
1679 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1680 has_psize + has_diffuse + has_specular + num_textures + 1;
1682 /* convert the declaration */
1683 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1684 if (!elements)
1685 return 0;
1687 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1688 idx = 0;
1689 if (has_pos) {
1690 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1691 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1692 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1694 else {
1695 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1696 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1698 elements[idx].UsageIndex = 0;
1699 idx++;
1701 if (has_blend && (num_blends > 0)) {
1702 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1703 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1704 else
1705 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1706 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1707 elements[idx].UsageIndex = 0;
1708 idx++;
1710 if (has_blend_idx) {
1711 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1712 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1713 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1714 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1715 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1716 else
1717 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1718 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1719 elements[idx].UsageIndex = 0;
1720 idx++;
1722 if (has_normal) {
1723 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1724 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1725 elements[idx].UsageIndex = 0;
1726 idx++;
1728 if (has_psize) {
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1730 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1731 elements[idx].UsageIndex = 0;
1732 idx++;
1734 if (has_diffuse) {
1735 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1736 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1737 elements[idx].UsageIndex = 0;
1738 idx++;
1740 if (has_specular) {
1741 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1742 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1743 elements[idx].UsageIndex = 1;
1744 idx++;
1746 for (idx2 = 0; idx2 < num_textures; idx2++) {
1747 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1748 switch (numcoords) {
1749 case WINED3DFVF_TEXTUREFORMAT1:
1750 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1751 break;
1752 case WINED3DFVF_TEXTUREFORMAT2:
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1754 break;
1755 case WINED3DFVF_TEXTUREFORMAT3:
1756 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1757 break;
1758 case WINED3DFVF_TEXTUREFORMAT4:
1759 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1760 break;
1762 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1763 elements[idx].UsageIndex = idx2;
1764 idx++;
1767 /* Now compute offsets, and initialize the rest of the fields */
1768 for (idx = 0, offset = 0; idx < size-1; idx++) {
1769 elements[idx].Stream = 0;
1770 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1771 elements[idx].Offset = offset;
1772 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1775 *ppVertexElements = elements;
1776 return size;
1779 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1780 WINED3DVERTEXELEMENT* elements = NULL;
1781 size_t size;
1782 DWORD hr;
1784 size = ConvertFvfToDeclaration(Fvf, &elements);
1785 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1787 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1788 HeapFree(GetProcessHeap(), 0, elements);
1789 if (hr != S_OK) return hr;
1791 return WINED3D_OK;
1794 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1795 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1797 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1798 HRESULT hr = WINED3D_OK;
1799 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1800 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1802 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1804 if (vertex_declaration) {
1805 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1808 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1810 if (WINED3D_OK != hr) {
1811 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1812 IWineD3DVertexShader_Release(*ppVertexShader);
1813 return WINED3DERR_INVALIDCALL;
1816 return WINED3D_OK;
1819 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1822 HRESULT hr = WINED3D_OK;
1824 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1825 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1826 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1827 if (WINED3D_OK == hr) {
1828 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1829 } else {
1830 WARN("(%p) : Failed to create pixel shader\n", This);
1833 return hr;
1836 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1837 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1838 IWineD3DPaletteImpl *object;
1839 HRESULT hr;
1840 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1842 /* Create the new object */
1843 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1844 if(!object) {
1845 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1846 return E_OUTOFMEMORY;
1849 object->lpVtbl = &IWineD3DPalette_Vtbl;
1850 object->ref = 1;
1851 object->Flags = Flags;
1852 object->parent = Parent;
1853 object->wineD3DDevice = This;
1854 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1856 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1858 if(!object->hpal) {
1859 HeapFree( GetProcessHeap(), 0, object);
1860 return E_OUTOFMEMORY;
1863 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1864 if(FAILED(hr)) {
1865 IWineD3DPalette_Release((IWineD3DPalette *) object);
1866 return hr;
1869 *Palette = (IWineD3DPalette *) object;
1871 return WINED3D_OK;
1874 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1876 IWineD3DSwapChainImpl *swapchain;
1877 HRESULT hr;
1878 DWORD state;
1880 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1881 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1883 /* TODO: Test if OpenGL is compiled in and loaded */
1885 TRACE("(%p) : Creating stateblock\n", This);
1886 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1887 hr = IWineD3DDevice_CreateStateBlock(iface,
1888 WINED3DSBT_INIT,
1889 (IWineD3DStateBlock **)&This->stateBlock,
1890 NULL);
1891 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1892 WARN("Failed to create stateblock\n");
1893 return hr;
1895 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1896 This->updateStateBlock = This->stateBlock;
1897 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1899 hr = allocate_shader_constants(This->updateStateBlock);
1900 if (WINED3D_OK != hr)
1901 return hr;
1903 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1904 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
1905 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
1907 /* Initialize the texture unit mapping to a 1:1 mapping */
1908 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
1909 if (state < GL_LIMITS(fragment_samplers)) {
1910 This->texUnitMap[state] = state;
1911 This->rev_tex_unit_map[state] = state;
1912 } else {
1913 This->texUnitMap[state] = -1;
1914 This->rev_tex_unit_map[state] = -1;
1918 /* Setup the implicit swapchain */
1919 TRACE("Creating implicit swapchain\n");
1920 hr=D3DCB_CreateAdditionalSwapChain((IUnknown *) This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
1921 if (FAILED(hr) || !swapchain) {
1922 WARN("Failed to create implicit swapchain\n");
1923 return hr;
1926 This->NumberOfSwapChains = 1;
1927 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
1928 if(!This->swapchains) {
1929 ERR("Out of memory!\n");
1930 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
1931 return E_OUTOFMEMORY;
1933 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
1935 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, swapchain->win_handle);
1937 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
1938 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
1939 This->render_targets[0] = swapchain->backBuffer[0];
1940 This->lastActiveRenderTarget = swapchain->backBuffer[0];
1942 else {
1943 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
1944 This->render_targets[0] = swapchain->frontBuffer;
1945 This->lastActiveRenderTarget = swapchain->frontBuffer;
1947 IWineD3DSurface_AddRef(This->render_targets[0]);
1948 This->activeContext = swapchain->context[0];
1949 This->lastThread = GetCurrentThreadId();
1951 /* Depth Stencil support */
1952 This->stencilBufferTarget = This->depthStencilBuffer;
1953 if (NULL != This->stencilBufferTarget) {
1954 IWineD3DSurface_AddRef(This->stencilBufferTarget);
1957 /* Set up some starting GL setup */
1958 ENTER_GL();
1960 /* Setup all the devices defaults */
1961 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
1962 #if 0
1963 IWineD3DImpl_CheckGraphicsMemory();
1964 #endif
1966 { /* Set a default viewport */
1967 WINED3DVIEWPORT vp;
1968 vp.X = 0;
1969 vp.Y = 0;
1970 vp.Width = pPresentationParameters->BackBufferWidth;
1971 vp.Height = pPresentationParameters->BackBufferHeight;
1972 vp.MinZ = 0.0f;
1973 vp.MaxZ = 1.0f;
1974 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
1977 /* Initialize the current view state */
1978 This->view_ident = 1;
1979 This->contexts[0]->last_was_rhw = 0;
1980 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
1981 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
1983 switch(wined3d_settings.offscreen_rendering_mode) {
1984 case ORM_FBO:
1985 case ORM_PBUFFER:
1986 This->offscreenBuffer = GL_BACK;
1987 break;
1989 case ORM_BACKBUFFER:
1991 if(GL_LIMITS(aux_buffers) > 0) {
1992 TRACE("Using auxilliary buffer for offscreen rendering\n");
1993 This->offscreenBuffer = GL_AUX0;
1994 } else {
1995 TRACE("Using back buffer for offscreen rendering\n");
1996 This->offscreenBuffer = GL_BACK;
2001 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2002 LEAVE_GL();
2004 /* Clear the screen */
2005 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2006 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2007 0x00, 1.0, 0);
2009 This->d3d_initialized = TRUE;
2010 return WINED3D_OK;
2013 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2015 int sampler;
2016 UINT i;
2017 TRACE("(%p)\n", This);
2019 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2021 /* I don't think that the interface guarants that the device is destroyed from the same thread
2022 * it was created. Thus make sure a context is active for the glDelete* calls
2024 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2026 TRACE("Deleting high order patches\n");
2027 for(i = 0; i < PATCHMAP_SIZE; i++) {
2028 struct list *e1, *e2;
2029 struct WineD3DRectPatch *patch;
2030 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2031 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2032 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2036 /* Delete the pbuffer context if there is any */
2037 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2039 /* Delete the mouse cursor texture */
2040 if(This->cursorTexture) {
2041 ENTER_GL();
2042 glDeleteTextures(1, &This->cursorTexture);
2043 LEAVE_GL();
2044 This->cursorTexture = 0;
2047 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2048 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2050 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2051 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2054 /* Release the update stateblock */
2055 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2056 if(This->updateStateBlock != This->stateBlock)
2057 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2059 This->updateStateBlock = NULL;
2061 { /* because were not doing proper internal refcounts releasing the primary state block
2062 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2063 to set this->stateBlock = NULL; first */
2064 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2065 This->stateBlock = NULL;
2067 /* Release the stateblock */
2068 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2069 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2073 /* Release the buffers (with sanity checks)*/
2074 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2075 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2076 if(This->depthStencilBuffer != This->stencilBufferTarget)
2077 FIXME("(%p) Something's still holding the depthStencilBuffer\n",This);
2079 This->stencilBufferTarget = NULL;
2081 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2082 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2083 /* This check is a bit silly, itshould be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2085 TRACE("Setting rendertarget to NULL\n");
2086 This->render_targets[0] = NULL;
2088 if (This->depthStencilBuffer) {
2089 if(D3DCB_DestroyDepthStencilSurface(This->depthStencilBuffer) > 0) {
2090 FIXME("(%p) Something's still holding the depthStencilBuffer\n", This);
2092 This->depthStencilBuffer = NULL;
2095 for(i=0; i < This->NumberOfSwapChains; i++) {
2096 TRACE("Releasing the implicit swapchain %d\n", i);
2097 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2098 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2102 HeapFree(GetProcessHeap(), 0, This->swapchains);
2103 This->swapchains = NULL;
2104 This->NumberOfSwapChains = 0;
2106 HeapFree(GetProcessHeap(), 0, This->render_targets);
2107 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2108 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2109 This->render_targets = NULL;
2110 This->fbo_color_attachments = NULL;
2111 This->draw_buffers = NULL;
2114 This->d3d_initialized = FALSE;
2115 return WINED3D_OK;
2118 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2120 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2122 /* Setup the window for fullscreen mode */
2123 if(fullscreen && !This->ddraw_fullscreen) {
2124 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2125 } else if(!fullscreen && This->ddraw_fullscreen) {
2126 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2129 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2130 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2131 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2132 * separately.
2134 This->ddraw_fullscreen = fullscreen;
2137 /* Enables thead safety in the wined3d device and its resources. Called by DirectDraw
2138 * from SetCooperativeLeven if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2139 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2141 * There is no way to deactivate thread safety once it is enabled
2143 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2146 /*For now just store the flag(needed in case of ddraw) */
2147 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2149 return;
2152 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2153 DEVMODEW devmode;
2154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2155 LONG ret;
2156 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2157 RECT clip_rc;
2159 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2161 /* Resize the screen even without a window:
2162 * The app could have unset it with SetCooperativeLevel, but not called
2163 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2164 * but we don't have any hwnd
2167 memset(&devmode, 0, sizeof(devmode));
2168 devmode.dmSize = sizeof(devmode);
2169 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2170 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2171 if(devmode.dmBitsPerPel == 24) devmode.dmBitsPerPel = 32;
2172 devmode.dmPelsWidth = pMode->Width;
2173 devmode.dmPelsHeight = pMode->Height;
2175 devmode.dmDisplayFrequency = pMode->RefreshRate;
2176 if (pMode->RefreshRate != 0) {
2177 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2180 /* Only change the mode if necessary */
2181 if( (This->ddraw_width == pMode->Width) &&
2182 (This->ddraw_height == pMode->Height) &&
2183 (This->ddraw_format == pMode->Format) &&
2184 (pMode->RefreshRate == 0) ) {
2185 return WINED3D_OK;
2188 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2189 if (ret != DISP_CHANGE_SUCCESSFUL) {
2190 if(devmode.dmDisplayFrequency != 0) {
2191 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2192 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2193 devmode.dmDisplayFrequency = 0;
2194 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2196 if(ret != DISP_CHANGE_SUCCESSFUL) {
2197 return WINED3DERR_NOTAVAILABLE;
2201 /* Store the new values */
2202 This->ddraw_width = pMode->Width;
2203 This->ddraw_height = pMode->Height;
2204 This->ddraw_format = pMode->Format;
2206 /* Only do this with a window of course */
2207 if(This->ddraw_window)
2208 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2210 /* And finally clip mouse to our screen */
2211 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2212 ClipCursor(&clip_rc);
2214 return WINED3D_OK;
2217 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2219 *ppD3D= This->wineD3D;
2220 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2221 IWineD3D_AddRef(*ppD3D);
2222 return WINED3D_OK;
2225 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2226 /** NOTE: There's a probably a hack-around for this one by putting as many pbuffers, VBOs (or whatever)
2227 * into the video ram as possible and seeing how many fit
2228 * you can also get the correct initial value from nvidia and ATI's driver via X
2229 * texture memory is video memory + AGP memory
2230 *******************/
2231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2232 static BOOL showfixmes = TRUE;
2233 if (showfixmes) {
2234 FIXME("(%p) : stub, simulating %dMB for now, returning %dMB left\n", This,
2235 (wined3d_settings.emulated_textureram/(1024*1024)),
2236 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2237 showfixmes = FALSE;
2239 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2240 (wined3d_settings.emulated_textureram/(1024*1024)),
2241 ((wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram) / (1024*1024)));
2242 /* return simulated texture memory left */
2243 return (wined3d_settings.emulated_textureram - wineD3DGlobalStatistics->glsurfaceram);
2248 /*****
2249 * Get / Set FVF
2250 *****/
2251 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2254 /* Update the current state block */
2255 This->updateStateBlock->changed.fvf = TRUE;
2257 if(This->updateStateBlock->fvf == fvf) {
2258 TRACE("Application is setting the old fvf over, nothing to do\n");
2259 return WINED3D_OK;
2262 This->updateStateBlock->fvf = fvf;
2263 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2265 return WINED3D_OK;
2269 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2271 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2272 *pfvf = This->stateBlock->fvf;
2273 return WINED3D_OK;
2276 /*****
2277 * Get / Set Stream Source
2278 *****/
2279 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2281 IWineD3DVertexBuffer *oldSrc;
2283 if (StreamNumber >= MAX_STREAMS) {
2284 WARN("Stream out of range %d\n", StreamNumber);
2285 return WINED3DERR_INVALIDCALL;
2288 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2289 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2291 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2293 if(oldSrc == pStreamData &&
2294 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2295 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2296 TRACE("Application is setting the old values over, nothing to do\n");
2297 return WINED3D_OK;
2300 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2301 if (pStreamData) {
2302 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2303 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2306 /* Handle recording of state blocks */
2307 if (This->isRecordingState) {
2308 TRACE("Recording... not performing anything\n");
2309 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2310 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2311 return WINED3D_OK;
2314 /* Need to do a getParent and pass the reffs up */
2315 /* MSDN says ..... When an application no longer holds a references to this interface, the interface will automatically be freed.
2316 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2317 so for now, just count internally */
2318 if (pStreamData != NULL) {
2319 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2320 InterlockedIncrement(&vbImpl->bindCount);
2321 IWineD3DVertexBuffer_AddRef(pStreamData);
2323 if (oldSrc != NULL) {
2324 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2325 IWineD3DVertexBuffer_Release(oldSrc);
2328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2330 return WINED3D_OK;
2333 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2336 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2337 This->stateBlock->streamSource[StreamNumber],
2338 This->stateBlock->streamOffset[StreamNumber],
2339 This->stateBlock->streamStride[StreamNumber]);
2341 if (StreamNumber >= MAX_STREAMS) {
2342 WARN("Stream out of range %d\n", StreamNumber);
2343 return WINED3DERR_INVALIDCALL;
2345 *pStream = This->stateBlock->streamSource[StreamNumber];
2346 *pStride = This->stateBlock->streamStride[StreamNumber];
2347 if (pOffset) {
2348 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2351 if (*pStream != NULL) {
2352 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2354 return WINED3D_OK;
2357 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2359 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2360 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2362 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2363 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2365 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2366 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2368 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2369 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2373 return WINED3D_OK;
2376 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2379 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2380 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2382 TRACE("(%p) : returning %d\n", This, *Divider);
2384 return WINED3D_OK;
2387 /*****
2388 * Get / Set & Multiply Transform
2389 *****/
2390 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2393 /* Most of this routine, comments included copied from ddraw tree initially: */
2394 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2396 /* Handle recording of state blocks */
2397 if (This->isRecordingState) {
2398 TRACE("Recording... not performing anything\n");
2399 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2400 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2401 return WINED3D_OK;
2405 * If the new matrix is the same as the current one,
2406 * we cut off any further processing. this seems to be a reasonable
2407 * optimization because as was noticed, some apps (warcraft3 for example)
2408 * tend towards setting the same matrix repeatedly for some reason.
2410 * From here on we assume that the new matrix is different, wherever it matters.
2412 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2413 TRACE("The app is setting the same matrix over again\n");
2414 return WINED3D_OK;
2415 } else {
2416 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2420 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2421 where ViewMat = Camera space, WorldMat = world space.
2423 In OpenGL, camera and world space is combined into GL_MODELVIEW
2424 matrix. The Projection matrix stay projection matrix.
2427 /* Capture the times we can just ignore the change for now */
2428 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrice */
2429 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2430 /* Handled by the state manager */
2433 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2434 return WINED3D_OK;
2437 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2439 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2440 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2441 return WINED3D_OK;
2444 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2445 WINED3DMATRIX *mat = NULL;
2446 WINED3DMATRIX temp;
2448 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2449 * below means it will be recorded in a state block change, but it
2450 * works regardless where it is recorded.
2451 * If this is found to be wrong, change to StateBlock.
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2454 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2456 if (State < HIGHEST_TRANSFORMSTATE)
2458 mat = &This->updateStateBlock->transforms[State];
2459 } else {
2460 FIXME("Unhandled transform state!!\n");
2463 multiply_matrix(&temp, mat, (const WINED3DMATRIX *) pMatrix);
2465 /* Apply change via set transform - will reapply to eg. lights this way */
2466 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2469 /*****
2470 * Get / Set Light
2471 *****/
2472 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2473 you can reference any indexes you want as long as that number max are enabled at any
2474 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2475 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2476 but when recording, just build a chain pretty much of commands to be replayed. */
2478 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2479 float rho;
2480 PLIGHTINFOEL *object = NULL;
2481 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2482 struct list *e;
2484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2485 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2487 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2488 * the gl driver.
2490 if(!pLight) {
2491 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2492 return WINED3DERR_INVALIDCALL;
2495 switch(pLight->Type) {
2496 case WINED3DLIGHT_POINT:
2497 case WINED3DLIGHT_SPOT:
2498 case WINED3DLIGHT_PARALLELPOINT:
2499 case WINED3DLIGHT_GLSPOT:
2500 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2501 * most wanted
2503 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2504 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2505 return WINED3DERR_INVALIDCALL;
2507 break;
2509 case WINED3DLIGHT_DIRECTIONAL:
2510 /* Ignores attenuation */
2511 break;
2513 default:
2514 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2515 return WINED3DERR_INVALIDCALL;
2518 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2519 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2520 if(object->OriginalIndex == Index) break;
2521 object = NULL;
2524 if(!object) {
2525 TRACE("Adding new light\n");
2526 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2527 if(!object) {
2528 ERR("Out of memory error when allocating a light\n");
2529 return E_OUTOFMEMORY;
2531 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2532 object->glIndex = -1;
2533 object->OriginalIndex = Index;
2534 object->changed = TRUE;
2537 /* Initialize the object */
2538 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,
2539 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2540 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2541 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2542 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2543 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2544 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2546 /* Save away the information */
2547 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2549 switch (pLight->Type) {
2550 case WINED3DLIGHT_POINT:
2551 /* Position */
2552 object->lightPosn[0] = pLight->Position.x;
2553 object->lightPosn[1] = pLight->Position.y;
2554 object->lightPosn[2] = pLight->Position.z;
2555 object->lightPosn[3] = 1.0f;
2556 object->cutoff = 180.0f;
2557 /* FIXME: Range */
2558 break;
2560 case WINED3DLIGHT_DIRECTIONAL:
2561 /* Direction */
2562 object->lightPosn[0] = -pLight->Direction.x;
2563 object->lightPosn[1] = -pLight->Direction.y;
2564 object->lightPosn[2] = -pLight->Direction.z;
2565 object->lightPosn[3] = 0.0;
2566 object->exponent = 0.0f;
2567 object->cutoff = 180.0f;
2568 break;
2570 case WINED3DLIGHT_SPOT:
2571 /* Position */
2572 object->lightPosn[0] = pLight->Position.x;
2573 object->lightPosn[1] = pLight->Position.y;
2574 object->lightPosn[2] = pLight->Position.z;
2575 object->lightPosn[3] = 1.0;
2577 /* Direction */
2578 object->lightDirn[0] = pLight->Direction.x;
2579 object->lightDirn[1] = pLight->Direction.y;
2580 object->lightDirn[2] = pLight->Direction.z;
2581 object->lightDirn[3] = 1.0;
2584 * opengl-ish and d3d-ish spot lights use too different models for the
2585 * light "intensity" as a function of the angle towards the main light direction,
2586 * so we only can approximate very roughly.
2587 * however spot lights are rather rarely used in games (if ever used at all).
2588 * furthermore if still used, probably nobody pays attention to such details.
2590 if (pLight->Falloff == 0) {
2591 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2592 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2593 * will always be 1.0 for both of them, and we don't have to care for the
2594 * rest of the rather complex calculation
2596 object->exponent = 0;
2597 } else {
2598 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2599 if (rho < 0.0001) rho = 0.0001f;
2600 object->exponent = -0.3/log(cos(rho/2));
2602 if (object->exponent > 128.0) {
2603 object->exponent = 128.0;
2605 object->cutoff = pLight->Phi*90/M_PI;
2607 /* FIXME: Range */
2608 break;
2610 default:
2611 FIXME("Unrecognized light type %d\n", pLight->Type);
2614 /* Update the live definitions if the light is currently assigned a glIndex */
2615 if (object->glIndex != -1 && !This->isRecordingState) {
2616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2618 return WINED3D_OK;
2621 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2622 PLIGHTINFOEL *lightInfo = NULL;
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2624 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2625 struct list *e;
2626 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2628 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2629 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2630 if(lightInfo->OriginalIndex == Index) break;
2631 lightInfo = NULL;
2634 if (lightInfo == NULL) {
2635 TRACE("Light information requested but light not defined\n");
2636 return WINED3DERR_INVALIDCALL;
2639 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2640 return WINED3D_OK;
2643 /*****
2644 * Get / Set Light Enable
2645 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2646 *****/
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2648 PLIGHTINFOEL *lightInfo = NULL;
2649 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2650 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2651 struct list *e;
2652 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2654 /* Tests show true = 128...not clear why */
2655 Enable = Enable? 128: 0;
2657 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2658 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2659 if(lightInfo->OriginalIndex == Index) break;
2660 lightInfo = NULL;
2662 TRACE("Found light: %p\n", lightInfo);
2664 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2665 if (lightInfo == NULL) {
2667 TRACE("Light enabled requested but light not defined, so defining one!\n");
2668 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2670 /* Search for it again! Should be fairly quick as near head of list */
2671 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2672 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2673 if(lightInfo->OriginalIndex == Index) break;
2674 lightInfo = NULL;
2676 if (lightInfo == NULL) {
2677 FIXME("Adding default lights has failed dismally\n");
2678 return WINED3DERR_INVALIDCALL;
2682 lightInfo->enabledChanged = TRUE;
2683 if(!Enable) {
2684 if(lightInfo->glIndex != -1) {
2685 if(!This->isRecordingState) {
2686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2689 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2690 lightInfo->glIndex = -1;
2691 } else {
2692 TRACE("Light already disabled, nothing to do\n");
2694 } else {
2695 if (lightInfo->glIndex != -1) {
2696 /* nop */
2697 TRACE("Nothing to do as light was enabled\n");
2698 } else {
2699 int i;
2700 /* Find a free gl light */
2701 for(i = 0; i < This->maxConcurrentLights; i++) {
2702 if(This->stateBlock->activeLights[i] == NULL) {
2703 This->stateBlock->activeLights[i] = lightInfo;
2704 lightInfo->glIndex = i;
2705 break;
2708 if(lightInfo->glIndex == -1) {
2709 ERR("Too many concurrently active lights\n");
2710 return WINED3DERR_INVALIDCALL;
2713 /* i == lightInfo->glIndex */
2714 if(!This->isRecordingState) {
2715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2720 return WINED3D_OK;
2723 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2725 PLIGHTINFOEL *lightInfo = NULL;
2726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2727 struct list *e;
2728 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2729 TRACE("(%p) : for idx(%d)\n", This, Index);
2731 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2732 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2733 if(lightInfo->OriginalIndex == Index) break;
2734 lightInfo = NULL;
2737 if (lightInfo == NULL) {
2738 TRACE("Light enabled state requested but light not defined\n");
2739 return WINED3DERR_INVALIDCALL;
2741 /* true is 128 according to SetLightEnable */
2742 *pEnable = lightInfo->glIndex != -1 ? 128 : 0;
2743 return WINED3D_OK;
2746 /*****
2747 * Get / Set Clip Planes
2748 *****/
2749 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2751 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2753 /* Validate Index */
2754 if (Index >= GL_LIMITS(clipplanes)) {
2755 TRACE("Application has requested clipplane this device doesn't support\n");
2756 return WINED3DERR_INVALIDCALL;
2759 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2761 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2762 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2763 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2764 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2765 TRACE("Application is setting old values over, nothing to do\n");
2766 return WINED3D_OK;
2769 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2770 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2771 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2772 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2774 /* Handle recording of state blocks */
2775 if (This->isRecordingState) {
2776 TRACE("Recording... not performing anything\n");
2777 return WINED3D_OK;
2780 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2782 return WINED3D_OK;
2785 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 TRACE("(%p) : for idx %d\n", This, Index);
2789 /* Validate Index */
2790 if (Index >= GL_LIMITS(clipplanes)) {
2791 TRACE("Application has requested clipplane this device doesn't support\n");
2792 return WINED3DERR_INVALIDCALL;
2795 pPlane[0] = This->stateBlock->clipplane[Index][0];
2796 pPlane[1] = This->stateBlock->clipplane[Index][1];
2797 pPlane[2] = This->stateBlock->clipplane[Index][2];
2798 pPlane[3] = This->stateBlock->clipplane[Index][3];
2799 return WINED3D_OK;
2802 /*****
2803 * Get / Set Clip Plane Status
2804 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2805 *****/
2806 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2807 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2808 FIXME("(%p) : stub\n", This);
2809 if (NULL == pClipStatus) {
2810 return WINED3DERR_INVALIDCALL;
2812 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2813 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2814 return WINED3D_OK;
2817 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2819 FIXME("(%p) : stub\n", This);
2820 if (NULL == pClipStatus) {
2821 return WINED3DERR_INVALIDCALL;
2823 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2824 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2825 return WINED3D_OK;
2828 /*****
2829 * Get / Set Material
2830 *****/
2831 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2834 This->updateStateBlock->changed.material = TRUE;
2835 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2837 /* Handle recording of state blocks */
2838 if (This->isRecordingState) {
2839 TRACE("Recording... not performing anything\n");
2840 return WINED3D_OK;
2843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2844 return WINED3D_OK;
2847 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2848 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2849 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2850 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2851 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2852 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2853 pMaterial->Ambient.b, pMaterial->Ambient.a);
2854 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2855 pMaterial->Specular.b, pMaterial->Specular.a);
2856 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2857 pMaterial->Emissive.b, pMaterial->Emissive.a);
2858 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2860 return WINED3D_OK;
2863 /*****
2864 * Get / Set Indices
2865 *****/
2866 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2868 IWineD3DIndexBuffer *oldIdxs;
2870 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2871 oldIdxs = This->updateStateBlock->pIndexData;
2873 This->updateStateBlock->changed.indices = TRUE;
2874 This->updateStateBlock->pIndexData = pIndexData;
2876 /* Handle recording of state blocks */
2877 if (This->isRecordingState) {
2878 TRACE("Recording... not performing anything\n");
2879 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2880 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2881 return WINED3D_OK;
2884 if(oldIdxs != pIndexData) {
2885 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
2886 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
2887 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
2889 return WINED3D_OK;
2892 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
2893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2895 *ppIndexData = This->stateBlock->pIndexData;
2897 /* up ref count on ppindexdata */
2898 if (*ppIndexData) {
2899 IWineD3DIndexBuffer_AddRef(*ppIndexData);
2900 TRACE("(%p) index data set to %p\n", This, ppIndexData);
2901 }else{
2902 TRACE("(%p) No index data set\n", This);
2904 TRACE("Returning %p\n", *ppIndexData);
2906 return WINED3D_OK;
2909 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
2910 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
2911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2912 TRACE("(%p)->(%d)\n", This, BaseIndex);
2914 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
2915 TRACE("Application is setting the old value over, nothing to do\n");
2916 return WINED3D_OK;
2919 This->updateStateBlock->baseVertexIndex = BaseIndex;
2921 if (This->isRecordingState) {
2922 TRACE("Recording... not performing anything\n");
2923 return WINED3D_OK;
2925 /* The base vertex index affects the stream sources */
2926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2927 return WINED3D_OK;
2930 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
2931 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2932 TRACE("(%p) : base_index %p\n", This, base_index);
2934 *base_index = This->stateBlock->baseVertexIndex;
2936 TRACE("Returning %u\n", *base_index);
2938 return WINED3D_OK;
2941 /*****
2942 * Get / Set Viewports
2943 *****/
2944 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2947 TRACE("(%p)\n", This);
2948 This->updateStateBlock->changed.viewport = TRUE;
2949 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
2951 /* Handle recording of state blocks */
2952 if (This->isRecordingState) {
2953 TRACE("Recording... not performing anything\n");
2954 return WINED3D_OK;
2957 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
2958 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
2960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
2961 return WINED3D_OK;
2965 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
2966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 TRACE("(%p)\n", This);
2968 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
2969 return WINED3D_OK;
2972 /*****
2973 * Get / Set Render States
2974 * TODO: Verify against dx9 definitions
2975 *****/
2976 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
2978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2979 DWORD oldValue = This->stateBlock->renderState[State];
2981 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
2983 This->updateStateBlock->changed.renderState[State] = TRUE;
2984 This->updateStateBlock->renderState[State] = Value;
2986 /* Handle recording of state blocks */
2987 if (This->isRecordingState) {
2988 TRACE("Recording... not performing anything\n");
2989 return WINED3D_OK;
2992 /* Compared here and not before the assignment to allow proper stateblock recording */
2993 if(Value == oldValue) {
2994 TRACE("Application is setting the old value over, nothing to do\n");
2995 } else {
2996 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
2999 return WINED3D_OK;
3002 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3004 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3005 *pValue = This->stateBlock->renderState[State];
3006 return WINED3D_OK;
3009 /*****
3010 * Get / Set Sampler States
3011 * TODO: Verify against dx9 definitions
3012 *****/
3014 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3016 DWORD oldValue;
3018 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3019 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3021 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3022 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3026 * SetSampler is designed to allow for more than the standard up to 8 textures
3027 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3028 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3030 * http://developer.nvidia.com/object/General_FAQ.html#t6
3032 * There are two new settings for GForce
3033 * the sampler one:
3034 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3035 * and the texture one:
3036 * GL_MAX_TEXTURE_COORDS_ARB.
3037 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3038 ******************/
3040 oldValue = This->stateBlock->samplerState[Sampler][Type];
3041 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3042 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3044 /* Handle recording of state blocks */
3045 if (This->isRecordingState) {
3046 TRACE("Recording... not performing anything\n");
3047 return WINED3D_OK;
3050 if(oldValue == Value) {
3051 TRACE("Application is setting the old value over, nothing to do\n");
3052 return WINED3D_OK;
3055 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3057 return WINED3D_OK;
3060 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3064 This, Sampler, debug_d3dsamplerstate(Type), Type);
3066 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3067 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3070 *Value = This->stateBlock->samplerState[Sampler][Type];
3071 TRACE("(%p) : Returning %#x\n", This, *Value);
3073 return WINED3D_OK;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 This->updateStateBlock->changed.scissorRect = TRUE;
3080 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3081 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3082 return WINED3D_OK;
3084 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3086 if(This->isRecordingState) {
3087 TRACE("Recording... not performing anything\n");
3088 return WINED3D_OK;
3091 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3093 return WINED3D_OK;
3096 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3099 memcpy(pRect, &This->updateStateBlock->scissorRect, sizeof(pRect));
3100 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3101 return WINED3D_OK;
3104 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3106 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3108 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3110 This->updateStateBlock->vertexDecl = pDecl;
3111 This->updateStateBlock->changed.vertexDecl = TRUE;
3113 if (This->isRecordingState) {
3114 TRACE("Recording... not performing anything\n");
3115 return WINED3D_OK;
3116 } else if(pDecl == oldDecl) {
3117 /* Checked after the assignment to allow proper stateblock recording */
3118 TRACE("Application is setting the old declaration over, nothing to do\n");
3119 return WINED3D_OK;
3122 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3131 *ppDecl = This->stateBlock->vertexDecl;
3132 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3133 return WINED3D_OK;
3136 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3140 This->updateStateBlock->vertexShader = pShader;
3141 This->updateStateBlock->changed.vertexShader = TRUE;
3143 if (This->isRecordingState) {
3144 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3145 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3146 TRACE("Recording... not performing anything\n");
3147 return WINED3D_OK;
3148 } else if(oldShader == pShader) {
3149 /* Checked here to allow proper stateblock recording */
3150 TRACE("App is setting the old shader over, nothing to do\n");
3151 return WINED3D_OK;
3154 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3155 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3156 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3158 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3160 return WINED3D_OK;
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3166 if (NULL == ppShader) {
3167 return WINED3DERR_INVALIDCALL;
3169 *ppShader = This->stateBlock->vertexShader;
3170 if( NULL != *ppShader)
3171 IWineD3DVertexShader_AddRef(*ppShader);
3173 TRACE("(%p) : returning %p\n", This, *ppShader);
3174 return WINED3D_OK;
3177 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3178 IWineD3DDevice *iface,
3179 UINT start,
3180 CONST BOOL *srcData,
3181 UINT count) {
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 int i, cnt = min(count, MAX_CONST_B - start);
3186 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3187 iface, srcData, start, count);
3189 if (srcData == NULL || cnt < 0)
3190 return WINED3DERR_INVALIDCALL;
3192 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3193 for (i = 0; i < cnt; i++)
3194 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3196 for (i = start; i < cnt + start; ++i) {
3197 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3202 return WINED3D_OK;
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3206 IWineD3DDevice *iface,
3207 UINT start,
3208 BOOL *dstData,
3209 UINT count) {
3211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3212 int cnt = min(count, MAX_CONST_B - start);
3214 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3215 iface, dstData, start, count);
3217 if (dstData == NULL || cnt < 0)
3218 return WINED3DERR_INVALIDCALL;
3220 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3221 return WINED3D_OK;
3224 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3225 IWineD3DDevice *iface,
3226 UINT start,
3227 CONST int *srcData,
3228 UINT count) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3231 int i, cnt = min(count, MAX_CONST_I - start);
3233 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3234 iface, srcData, start, count);
3236 if (srcData == NULL || cnt < 0)
3237 return WINED3DERR_INVALIDCALL;
3239 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3240 for (i = 0; i < cnt; i++)
3241 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3242 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3244 for (i = start; i < cnt + start; ++i) {
3245 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3250 return WINED3D_OK;
3253 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3254 IWineD3DDevice *iface,
3255 UINT start,
3256 int *dstData,
3257 UINT count) {
3259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 int cnt = min(count, MAX_CONST_I - start);
3262 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3263 iface, dstData, start, count);
3265 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3266 return WINED3DERR_INVALIDCALL;
3268 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3269 return WINED3D_OK;
3272 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3273 IWineD3DDevice *iface,
3274 UINT start,
3275 CONST float *srcData,
3276 UINT count) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 int i;
3281 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3282 iface, srcData, start, count);
3284 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3285 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3286 return WINED3DERR_INVALIDCALL;
3288 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3289 if(TRACE_ON(d3d)) {
3290 for (i = 0; i < count; i++)
3291 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3292 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3295 for (i = start; i < count + start; ++i) {
3296 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3297 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3298 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3299 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3300 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3302 ptr->idx[ptr->count++] = i;
3303 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3309 return WINED3D_OK;
3312 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3313 IWineD3DDevice *iface,
3314 UINT start,
3315 float *dstData,
3316 UINT count) {
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3321 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3322 iface, dstData, start, count);
3324 if (dstData == NULL || cnt < 0)
3325 return WINED3DERR_INVALIDCALL;
3327 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3328 return WINED3D_OK;
3331 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3332 DWORD i;
3333 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3338 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3339 int i = This->rev_tex_unit_map[unit];
3340 int j = This->texUnitMap[stage];
3342 This->texUnitMap[stage] = unit;
3343 if (i != -1 && i != stage) {
3344 This->texUnitMap[i] = -1;
3347 This->rev_tex_unit_map[unit] = stage;
3348 if (j != -1 && j != unit) {
3349 This->rev_tex_unit_map[j] = -1;
3353 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3354 int i;
3356 for (i = 0; i < MAX_TEXTURES; ++i) {
3357 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3358 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3359 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3360 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3361 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3362 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3363 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3364 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3366 if (color_op == WINED3DTOP_DISABLE) {
3367 /* Not used, and disable higher stages */
3368 while (i < MAX_TEXTURES) {
3369 This->fixed_function_usage_map[i] = FALSE;
3370 ++i;
3372 break;
3375 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3376 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3377 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3378 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3379 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3380 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3381 This->fixed_function_usage_map[i] = TRUE;
3382 } else {
3383 This->fixed_function_usage_map[i] = FALSE;
3386 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3387 This->fixed_function_usage_map[i+1] = TRUE;
3392 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3393 int i, tex;
3395 device_update_fixed_function_usage_map(This);
3397 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3398 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3399 if (!This->fixed_function_usage_map[i]) continue;
3401 if (This->texUnitMap[i] != i) {
3402 device_map_stage(This, i, i);
3403 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3404 markTextureStagesDirty(This, i);
3407 return;
3410 /* Now work out the mapping */
3411 tex = 0;
3412 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3413 if (!This->fixed_function_usage_map[i]) continue;
3415 if (This->texUnitMap[i] != tex) {
3416 device_map_stage(This, i, tex);
3417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3418 markTextureStagesDirty(This, i);
3421 ++tex;
3425 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3426 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3427 int i;
3429 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3430 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3431 device_map_stage(This, i, i);
3432 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3433 if (i < MAX_TEXTURES) {
3434 markTextureStagesDirty(This, i);
3440 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3441 int current_mapping = This->rev_tex_unit_map[unit];
3443 if (current_mapping == -1) {
3444 /* Not currently used */
3445 return TRUE;
3448 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3449 /* Used by a fragment sampler */
3451 if (!pshader_sampler_tokens) {
3452 /* No pixel shader, check fixed function */
3453 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3456 /* Pixel shader, check the shader's sampler map */
3457 return !pshader_sampler_tokens[current_mapping];
3460 /* Used by a vertex sampler */
3461 return !vshader_sampler_tokens[current_mapping];
3464 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3465 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3466 DWORD *pshader_sampler_tokens = NULL;
3467 int start = GL_LIMITS(combined_samplers) - 1;
3468 int i;
3470 if (ps) {
3471 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3473 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3474 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3475 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3478 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3479 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3480 if (vshader_sampler_tokens[i]) {
3481 if (This->texUnitMap[vsampler_idx] != -1) {
3482 /* Already mapped somewhere */
3483 continue;
3486 while (start >= 0) {
3487 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3488 device_map_stage(This, vsampler_idx, start);
3489 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3491 --start;
3492 break;
3495 --start;
3501 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3502 BOOL vs = use_vs(This);
3503 BOOL ps = use_ps(This);
3505 * Rules are:
3506 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3507 * that would be really messy and require shader recompilation
3508 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3509 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3511 if (ps) {
3512 device_map_psamplers(This);
3513 } else {
3514 device_map_fixed_function_samplers(This);
3517 if (vs) {
3518 device_map_vsamplers(This, ps);
3522 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3524 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3525 This->updateStateBlock->pixelShader = pShader;
3526 This->updateStateBlock->changed.pixelShader = TRUE;
3528 /* Handle recording of state blocks */
3529 if (This->isRecordingState) {
3530 TRACE("Recording... not performing anything\n");
3533 if (This->isRecordingState) {
3534 TRACE("Recording... not performing anything\n");
3535 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3536 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3537 return WINED3D_OK;
3540 if(pShader == oldShader) {
3541 TRACE("App is setting the old pixel shader over, nothing to do\n");
3542 return WINED3D_OK;
3545 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3546 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3548 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3551 return WINED3D_OK;
3554 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3557 if (NULL == ppShader) {
3558 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3559 return WINED3DERR_INVALIDCALL;
3562 *ppShader = This->stateBlock->pixelShader;
3563 if (NULL != *ppShader) {
3564 IWineD3DPixelShader_AddRef(*ppShader);
3566 TRACE("(%p) : returning %p\n", This, *ppShader);
3567 return WINED3D_OK;
3570 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3571 IWineD3DDevice *iface,
3572 UINT start,
3573 CONST BOOL *srcData,
3574 UINT count) {
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 int i, cnt = min(count, MAX_CONST_B - start);
3579 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3580 iface, srcData, start, count);
3582 if (srcData == NULL || cnt < 0)
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3586 for (i = 0; i < cnt; i++)
3587 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3589 for (i = start; i < cnt + start; ++i) {
3590 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3593 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3595 return WINED3D_OK;
3598 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3599 IWineD3DDevice *iface,
3600 UINT start,
3601 BOOL *dstData,
3602 UINT count) {
3604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3605 int cnt = min(count, MAX_CONST_B - start);
3607 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3608 iface, dstData, start, count);
3610 if (dstData == NULL || cnt < 0)
3611 return WINED3DERR_INVALIDCALL;
3613 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3614 return WINED3D_OK;
3617 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3618 IWineD3DDevice *iface,
3619 UINT start,
3620 CONST int *srcData,
3621 UINT count) {
3623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3624 int i, cnt = min(count, MAX_CONST_I - start);
3626 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3627 iface, srcData, start, count);
3629 if (srcData == NULL || cnt < 0)
3630 return WINED3DERR_INVALIDCALL;
3632 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3633 for (i = 0; i < cnt; i++)
3634 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3635 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3637 for (i = start; i < cnt + start; ++i) {
3638 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3643 return WINED3D_OK;
3646 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3647 IWineD3DDevice *iface,
3648 UINT start,
3649 int *dstData,
3650 UINT count) {
3652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3653 int cnt = min(count, MAX_CONST_I - start);
3655 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3656 iface, dstData, start, count);
3658 if (dstData == NULL || cnt < 0)
3659 return WINED3DERR_INVALIDCALL;
3661 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3662 return WINED3D_OK;
3665 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3666 IWineD3DDevice *iface,
3667 UINT start,
3668 CONST float *srcData,
3669 UINT count) {
3671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3672 int i;
3674 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3675 iface, srcData, start, count);
3677 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3678 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3679 return WINED3DERR_INVALIDCALL;
3681 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3682 if(TRACE_ON(d3d)) {
3683 for (i = 0; i < count; i++)
3684 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3685 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3688 for (i = start; i < count + start; ++i) {
3689 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3690 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3691 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3692 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3693 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3695 ptr->idx[ptr->count++] = i;
3696 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3700 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3702 return WINED3D_OK;
3705 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3706 IWineD3DDevice *iface,
3707 UINT start,
3708 float *dstData,
3709 UINT count) {
3711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3712 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3714 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3715 iface, dstData, start, count);
3717 if (dstData == NULL || cnt < 0)
3718 return WINED3DERR_INVALIDCALL;
3720 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3721 return WINED3D_OK;
3724 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3725 static HRESULT
3726 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3727 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3728 unsigned int i;
3729 DWORD DestFVF = dest->fvf;
3730 WINED3DVIEWPORT vp;
3731 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3732 BOOL doClip;
3733 int numTextures;
3735 if (lpStrideData->u.s.normal.lpData) {
3736 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3739 if (lpStrideData->u.s.position.lpData == NULL) {
3740 ERR("Source has no position mask\n");
3741 return WINED3DERR_INVALIDCALL;
3744 /* We might access VBOs from this code, so hold the lock */
3745 ENTER_GL();
3747 if (dest->resource.allocatedMemory == NULL) {
3748 /* This may happen if we do direct locking into a vbo. Unlikely,
3749 * but theoretically possible(ddraw processvertices test)
3751 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3752 if(!dest->resource.allocatedMemory) {
3753 LEAVE_GL();
3754 ERR("Out of memory\n");
3755 return E_OUTOFMEMORY;
3757 if(dest->vbo) {
3758 void *src;
3759 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3760 checkGLcall("glBindBufferARB");
3761 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3762 if(src) {
3763 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3765 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3766 checkGLcall("glUnmapBufferARB");
3770 /* Get a pointer into the destination vbo(create one if none exists) and
3771 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3773 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3774 CreateVBO(dest);
3777 if(dest->vbo) {
3778 unsigned char extrabytes = 0;
3779 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3780 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3781 * this may write 4 extra bytes beyond the area that should be written
3783 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3784 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3785 if(!dest_conv_addr) {
3786 ERR("Out of memory\n");
3787 /* Continue without storing converted vertices */
3789 dest_conv = dest_conv_addr;
3792 /* Should I clip?
3793 * a) WINED3DRS_CLIPPING is enabled
3794 * b) WINED3DVOP_CLIP is passed
3796 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3797 static BOOL warned = FALSE;
3799 * The clipping code is not quite correct. Some things need
3800 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3801 * so disable clipping for now.
3802 * (The graphics in Half-Life are broken, and my processvertices
3803 * test crashes with IDirect3DDevice3)
3804 doClip = TRUE;
3806 doClip = FALSE;
3807 if(!warned) {
3808 warned = TRUE;
3809 FIXME("Clipping is broken and disabled for now\n");
3811 } else doClip = FALSE;
3812 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3814 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3815 WINED3DTS_VIEW,
3816 &view_mat);
3817 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3818 WINED3DTS_PROJECTION,
3819 &proj_mat);
3820 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3821 WINED3DTS_WORLDMATRIX(0),
3822 &world_mat);
3824 TRACE("View mat:\n");
3825 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);
3826 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);
3827 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);
3828 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);
3830 TRACE("Proj mat:\n");
3831 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);
3832 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);
3833 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);
3834 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);
3836 TRACE("World mat:\n");
3837 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);
3838 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);
3839 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);
3840 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);
3842 /* Get the viewport */
3843 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3844 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3845 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3847 multiply_matrix(&mat,&view_mat,&world_mat);
3848 multiply_matrix(&mat,&proj_mat,&mat);
3850 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3852 for (i = 0; i < dwCount; i+= 1) {
3853 unsigned int tex_index;
3855 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3856 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3857 /* The position first */
3858 float *p =
3859 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3860 float x, y, z, rhw;
3861 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3863 /* Multiplication with world, view and projection matrix */
3864 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);
3865 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);
3866 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);
3867 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);
3869 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
3871 /* WARNING: The following things are taken from d3d7 and were not yet checked
3872 * against d3d8 or d3d9!
3875 /* Clipping conditions: From
3876 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
3878 * A vertex is clipped if it does not match the following requirements
3879 * -rhw < x <= rhw
3880 * -rhw < y <= rhw
3881 * 0 < z <= rhw
3882 * 0 < rhw ( Not in d3d7, but tested in d3d7)
3884 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
3885 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
3889 if( !doClip ||
3890 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
3891 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
3892 ( rhw > eps ) ) ) {
3894 /* "Normal" viewport transformation (not clipped)
3895 * 1) The values are divided by rhw
3896 * 2) The y axis is negative, so multiply it with -1
3897 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
3898 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
3899 * 4) Multiply x with Width/2 and add Width/2
3900 * 5) The same for the height
3901 * 6) Add the viewpoint X and Y to the 2D coordinates and
3902 * The minimum Z value to z
3903 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
3905 * Well, basically it's simply a linear transformation into viewport
3906 * coordinates
3909 x /= rhw;
3910 y /= rhw;
3911 z /= rhw;
3913 y *= -1;
3915 x *= vp.Width / 2;
3916 y *= vp.Height / 2;
3917 z *= vp.MaxZ - vp.MinZ;
3919 x += vp.Width / 2 + vp.X;
3920 y += vp.Height / 2 + vp.Y;
3921 z += vp.MinZ;
3923 rhw = 1 / rhw;
3924 } else {
3925 /* That vertex got clipped
3926 * Contrary to OpenGL it is not dropped completely, it just
3927 * undergoes a different calculation.
3929 TRACE("Vertex got clipped\n");
3930 x += rhw;
3931 y += rhw;
3933 x /= 2;
3934 y /= 2;
3936 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
3937 * outside of the main vertex buffer memory. That needs some more
3938 * investigation...
3942 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
3945 ( (float *) dest_ptr)[0] = x;
3946 ( (float *) dest_ptr)[1] = y;
3947 ( (float *) dest_ptr)[2] = z;
3948 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
3950 dest_ptr += 3 * sizeof(float);
3952 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3953 dest_ptr += sizeof(float);
3956 if(dest_conv) {
3957 float w = 1 / rhw;
3958 ( (float *) dest_conv)[0] = x * w;
3959 ( (float *) dest_conv)[1] = y * w;
3960 ( (float *) dest_conv)[2] = z * w;
3961 ( (float *) dest_conv)[3] = w;
3963 dest_conv += 3 * sizeof(float);
3965 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
3966 dest_conv += sizeof(float);
3970 if (DestFVF & WINED3DFVF_PSIZE) {
3971 dest_ptr += sizeof(DWORD);
3972 if(dest_conv) dest_conv += sizeof(DWORD);
3974 if (DestFVF & WINED3DFVF_NORMAL) {
3975 float *normal =
3976 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
3977 /* AFAIK this should go into the lighting information */
3978 FIXME("Didn't expect the destination to have a normal\n");
3979 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
3980 if(dest_conv) {
3981 copy_and_next(dest_conv, normal, 3 * sizeof(float));
3985 if (DestFVF & WINED3DFVF_DIFFUSE) {
3986 DWORD *color_d =
3987 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
3988 if(!color_d) {
3989 static BOOL warned = FALSE;
3991 if(!warned) {
3992 ERR("No diffuse color in source, but destination has one\n");
3993 warned = TRUE;
3996 *( (DWORD *) dest_ptr) = 0xffffffff;
3997 dest_ptr += sizeof(DWORD);
3999 if(dest_conv) {
4000 *( (DWORD *) dest_conv) = 0xffffffff;
4001 dest_conv += sizeof(DWORD);
4004 else {
4005 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4006 if(dest_conv) {
4007 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4008 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4009 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4010 dest_conv += sizeof(DWORD);
4015 if (DestFVF & WINED3DFVF_SPECULAR) {
4016 /* What's the color value in the feedback buffer? */
4017 DWORD *color_s =
4018 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4019 if(!color_s) {
4020 static BOOL warned = FALSE;
4022 if(!warned) {
4023 ERR("No specular color in source, but destination has one\n");
4024 warned = TRUE;
4027 *( (DWORD *) dest_ptr) = 0xFF000000;
4028 dest_ptr += sizeof(DWORD);
4030 if(dest_conv) {
4031 *( (DWORD *) dest_conv) = 0xFF000000;
4032 dest_conv += sizeof(DWORD);
4035 else {
4036 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4037 if(dest_conv) {
4038 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4039 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4040 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4041 dest_conv += sizeof(DWORD);
4046 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4047 float *tex_coord =
4048 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4049 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4050 if(!tex_coord) {
4051 ERR("No source texture, but destination requests one\n");
4052 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4053 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4055 else {
4056 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4057 if(dest_conv) {
4058 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4064 if(dest_conv) {
4065 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4066 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4067 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4068 dwCount * get_flexible_vertex_size(DestFVF),
4069 dest_conv_addr));
4070 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4071 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4074 LEAVE_GL();
4076 return WINED3D_OK;
4078 #undef copy_and_next
4080 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4082 WineDirect3DVertexStridedData strided;
4083 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4084 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4086 if(pVertexDecl) {
4087 ERR("Output vertex declaration not implemented yet\n");
4090 /* Need any context to write to the vbo. In a non-multithreaded environment a context is there anyway,
4091 * and this call is quite performance critical, so don't call needlessly
4093 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4094 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4097 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4098 * control the streamIsUP flag, thus restore it afterwards.
4100 This->stateBlock->streamIsUP = FALSE;
4101 memset(&strided, 0, sizeof(strided));
4102 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4103 This->stateBlock->streamIsUP = streamWasUP;
4105 if(vbo || SrcStartIndex) {
4106 unsigned int i;
4107 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcesVerticse are
4108 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4110 * Also get the start index in, but only loop over all elements if there's something to add at all.
4112 #define FIXSRC(type) \
4113 if(strided.u.s.type.VBO) { \
4114 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4115 strided.u.s.type.VBO = 0; \
4116 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4117 ENTER_GL(); \
4118 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4119 vb->vbo = 0; \
4120 LEAVE_GL(); \
4122 if(strided.u.s.type.lpData) { \
4123 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4125 FIXSRC(position);
4126 FIXSRC(blendWeights);
4127 FIXSRC(blendMatrixIndices);
4128 FIXSRC(normal);
4129 FIXSRC(pSize);
4130 FIXSRC(diffuse);
4131 FIXSRC(specular);
4132 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4133 FIXSRC(texCoords[i]);
4135 FIXSRC(position2);
4136 FIXSRC(normal2);
4137 FIXSRC(tangent);
4138 FIXSRC(binormal);
4139 FIXSRC(tessFactor);
4140 FIXSRC(fog);
4141 FIXSRC(depth);
4142 FIXSRC(sample);
4143 #undef FIXSRC
4146 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4149 /*****
4150 * Get / Set Texture Stage States
4151 * TODO: Verify against dx9 definitions
4152 *****/
4153 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4155 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4157 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4159 if (Stage >= MAX_TEXTURES) {
4160 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4161 return WINED3D_OK;
4164 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4165 This->updateStateBlock->textureState[Stage][Type] = Value;
4167 if (This->isRecordingState) {
4168 TRACE("Recording... not performing anything\n");
4169 return WINED3D_OK;
4172 /* Checked after the assignments to allow proper stateblock recording */
4173 if(oldValue == Value) {
4174 TRACE("App is setting the old value over, nothing to do\n");
4175 return WINED3D_OK;
4178 if(Stage > This->stateBlock->lowest_disabled_stage &&
4179 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4180 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4181 * Changes in other states are important on disabled stages too
4183 return WINED3D_OK;
4186 if(Type == WINED3DTSS_COLOROP) {
4187 int i;
4189 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4190 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4191 * they have to be disabled
4193 * The current stage is dirtified below.
4195 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4196 TRACE("Additionally dirtifying stage %d\n", i);
4197 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4199 This->stateBlock->lowest_disabled_stage = Stage;
4200 TRACE("New lowest disabled: %d\n", Stage);
4201 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4202 /* Previously disabled stage enabled. Stages above it may need enabling
4203 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4204 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4206 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4209 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4210 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4211 break;
4213 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4216 This->stateBlock->lowest_disabled_stage = i;
4217 TRACE("New lowest disabled: %d\n", i);
4219 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4220 /* TODO: Built a stage -> texture unit mapping for register combiners */
4224 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4226 return WINED3D_OK;
4229 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4231 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4232 *pValue = This->updateStateBlock->textureState[Stage][Type];
4233 return WINED3D_OK;
4236 /*****
4237 * Get / Set Texture
4238 *****/
4239 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4241 IWineD3DBaseTexture *oldTexture;
4243 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4245 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4246 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4249 oldTexture = This->updateStateBlock->textures[Stage];
4251 if(pTexture != NULL) {
4252 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4254 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4255 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4256 return WINED3DERR_INVALIDCALL;
4258 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4261 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4262 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4264 This->updateStateBlock->changed.textures[Stage] = TRUE;
4265 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4266 This->updateStateBlock->textures[Stage] = pTexture;
4268 /* Handle recording of state blocks */
4269 if (This->isRecordingState) {
4270 TRACE("Recording... not performing anything\n");
4271 return WINED3D_OK;
4274 if(oldTexture == pTexture) {
4275 TRACE("App is setting the same texture again, nothing to do\n");
4276 return WINED3D_OK;
4279 /** NOTE: MSDN says that setTexture increases the reference count,
4280 * and the the application must set the texture back to null (or have a leaky application),
4281 * This means we should pass the refcount up to the parent
4282 *******************************/
4283 if (NULL != This->updateStateBlock->textures[Stage]) {
4284 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4285 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4287 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4288 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4289 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4290 * so the COLOROP and ALPHAOP have to be dirtified.
4292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4295 if(bindCount == 1) {
4296 new->baseTexture.sampler = Stage;
4298 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4302 if (NULL != oldTexture) {
4303 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4304 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4306 IWineD3DBaseTexture_Release(oldTexture);
4307 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4312 if(bindCount && old->baseTexture.sampler == Stage) {
4313 int i;
4314 /* Have to do a search for the other sampler(s) where the texture is bound to
4315 * Shouldn't happen as long as apps bind a texture only to one stage
4317 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4318 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4319 if(This->updateStateBlock->textures[i] == oldTexture) {
4320 old->baseTexture.sampler = i;
4321 break;
4327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4329 return WINED3D_OK;
4332 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4335 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4337 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4338 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4341 *ppTexture=This->stateBlock->textures[Stage];
4342 if (*ppTexture)
4343 IWineD3DBaseTexture_AddRef(*ppTexture);
4345 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4347 return WINED3D_OK;
4350 /*****
4351 * Get Back Buffer
4352 *****/
4353 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4354 IWineD3DSurface **ppBackBuffer) {
4355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4356 IWineD3DSwapChain *swapChain;
4357 HRESULT hr;
4359 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4361 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4362 if (hr == WINED3D_OK) {
4363 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4364 IWineD3DSwapChain_Release(swapChain);
4365 } else {
4366 *ppBackBuffer = NULL;
4368 return hr;
4371 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4373 WARN("(%p) : stub, calling idirect3d for now\n", This);
4374 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4377 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4379 IWineD3DSwapChain *swapChain;
4380 HRESULT hr;
4382 if(iSwapChain > 0) {
4383 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
4384 if (hr == WINED3D_OK) {
4385 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4386 IWineD3DSwapChain_Release(swapChain);
4387 } else {
4388 FIXME("(%p) Error getting display mode\n", This);
4390 } else {
4391 /* Don't read the real display mode,
4392 but return the stored mode instead. X11 can't change the color
4393 depth, and some apps are pretty angry if they SetDisplayMode from
4394 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4396 Also don't relay to the swapchain because with ddraw it's possible
4397 that there isn't a swapchain at all */
4398 pMode->Width = This->ddraw_width;
4399 pMode->Height = This->ddraw_height;
4400 pMode->Format = This->ddraw_format;
4401 pMode->RefreshRate = 0;
4402 hr = WINED3D_OK;
4405 return hr;
4408 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4410 TRACE("(%p)->(%p)\n", This, hWnd);
4412 if(This->ddraw_fullscreen) {
4413 if(This->ddraw_window && This->ddraw_window != hWnd) {
4414 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4416 if(hWnd && This->ddraw_window != hWnd) {
4417 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4421 This->ddraw_window = hWnd;
4422 return WINED3D_OK;
4425 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4427 TRACE("(%p)->(%p)\n", This, hWnd);
4429 *hWnd = This->ddraw_window;
4430 return WINED3D_OK;
4433 /*****
4434 * Stateblock related functions
4435 *****/
4437 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4439 IWineD3DStateBlockImpl *object;
4440 HRESULT temp_result;
4441 int i;
4443 TRACE("(%p)\n", This);
4445 if (This->isRecordingState) {
4446 return WINED3DERR_INVALIDCALL;
4449 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4450 if (NULL == object ) {
4451 FIXME("(%p)Error allocating memory for stateblock\n", This);
4452 return E_OUTOFMEMORY;
4454 TRACE("(%p) created object %p\n", This, object);
4455 object->wineD3DDevice= This;
4456 /** FIXME: object->parent = parent; **/
4457 object->parent = NULL;
4458 object->blockType = WINED3DSBT_RECORDED;
4459 object->ref = 1;
4460 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4462 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4463 list_init(&object->lightMap[i]);
4466 temp_result = allocate_shader_constants(object);
4467 if (WINED3D_OK != temp_result)
4468 return temp_result;
4470 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4471 This->updateStateBlock = object;
4472 This->isRecordingState = TRUE;
4474 TRACE("(%p) recording stateblock %p\n",This , object);
4475 return WINED3D_OK;
4478 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 unsigned int i, j;
4481 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4483 if (!This->isRecordingState) {
4484 FIXME("(%p) not recording! returning error\n", This);
4485 *ppStateBlock = NULL;
4486 return WINED3DERR_INVALIDCALL;
4489 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4490 if(object->changed.renderState[i]) {
4491 object->contained_render_states[object->num_contained_render_states] = i;
4492 object->num_contained_render_states++;
4495 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4496 if(object->changed.transform[i]) {
4497 object->contained_transform_states[object->num_contained_transform_states] = i;
4498 object->num_contained_transform_states++;
4501 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4502 if(object->changed.vertexShaderConstantsF[i]) {
4503 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4504 object->num_contained_vs_consts_f++;
4507 for(i = 0; i < MAX_CONST_I; i++) {
4508 if(object->changed.vertexShaderConstantsI[i]) {
4509 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4510 object->num_contained_vs_consts_i++;
4513 for(i = 0; i < MAX_CONST_B; i++) {
4514 if(object->changed.vertexShaderConstantsB[i]) {
4515 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4516 object->num_contained_vs_consts_b++;
4519 for(i = 0; i < MAX_CONST_I; i++) {
4520 if(object->changed.pixelShaderConstantsI[i]) {
4521 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4522 object->num_contained_ps_consts_i++;
4525 for(i = 0; i < MAX_CONST_B; i++) {
4526 if(object->changed.pixelShaderConstantsB[i]) {
4527 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4528 object->num_contained_ps_consts_b++;
4531 for(i = 0; i < MAX_TEXTURES; i++) {
4532 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4533 if(object->changed.textureState[i][j]) {
4534 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4535 object->contained_tss_states[object->num_contained_tss_states].state = j;
4536 object->num_contained_tss_states++;
4540 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4541 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4542 if(object->changed.samplerState[i][j]) {
4543 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4544 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4545 object->num_contained_sampler_states++;
4550 *ppStateBlock = (IWineD3DStateBlock*) object;
4551 This->isRecordingState = FALSE;
4552 This->updateStateBlock = This->stateBlock;
4553 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4554 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4555 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4556 return WINED3D_OK;
4559 /*****
4560 * Scene related functions
4561 *****/
4562 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4563 /* At the moment we have no need for any functionality at the beginning
4564 of a scene */
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p)\n", This);
4568 if(This->inScene) {
4569 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4570 return WINED3DERR_INVALIDCALL;
4572 This->inScene = TRUE;
4573 return WINED3D_OK;
4576 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4578 TRACE("(%p)\n", This);
4580 if(!This->inScene) {
4581 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4582 return WINED3DERR_INVALIDCALL;
4585 if(This->createParms.BehaviorFlags & WINED3DCREATE_MULTITHREADED) {
4586 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4588 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4589 ENTER_GL();
4590 glFlush();
4591 checkGLcall("glFlush");
4592 LEAVE_GL();
4594 This->inScene = FALSE;
4595 return WINED3D_OK;
4598 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4599 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4600 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4602 IWineD3DSwapChain *swapChain = NULL;
4603 int i;
4604 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4606 TRACE("(%p) Presenting the frame\n", This);
4608 for(i = 0 ; i < swapchains ; i ++) {
4610 IWineD3DDeviceImpl_GetSwapChain(iface, i , (IWineD3DSwapChain **)&swapChain);
4611 TRACE("presentinng chain %d, %p\n", i, swapChain);
4612 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4613 IWineD3DSwapChain_Release(swapChain);
4616 return WINED3D_OK;
4619 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4620 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4622 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4624 GLbitfield glMask = 0;
4625 unsigned int i;
4626 CONST WINED3DRECT* curRect;
4628 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4629 Count, pRects, Flags, Color, Z, Stencil);
4631 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4632 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4633 /* TODO: What about depth stencil buffers without stencil bits? */
4634 return WINED3DERR_INVALIDCALL;
4637 /* This is for offscreen rendering as well as for multithreading, thus activate the set render target
4638 * and not the last active one.
4640 ActivateContext(This, This->render_targets[0], CTXUSAGE_CLEAR);
4641 ENTER_GL();
4643 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4644 apply_fbo_state(iface);
4647 if (Count > 0 && pRects) {
4648 curRect = pRects;
4649 } else {
4650 curRect = NULL;
4653 /* Only set the values up once, as they are not changing */
4654 if (Flags & WINED3DCLEAR_STENCIL) {
4655 glClearStencil(Stencil);
4656 checkGLcall("glClearStencil");
4657 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4658 glStencilMask(0xFFFFFFFF);
4661 if (Flags & WINED3DCLEAR_ZBUFFER) {
4662 glDepthMask(GL_TRUE);
4663 glClearDepth(Z);
4664 checkGLcall("glClearDepth");
4665 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4669 if (Flags & WINED3DCLEAR_TARGET) {
4670 TRACE("Clearing screen with glClear to color %x\n", Color);
4671 glClearColor(D3DCOLOR_R(Color),
4672 D3DCOLOR_G(Color),
4673 D3DCOLOR_B(Color),
4674 D3DCOLOR_A(Color));
4675 checkGLcall("glClearColor");
4677 /* Clear ALL colors! */
4678 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4679 glMask = glMask | GL_COLOR_BUFFER_BIT;
4682 if (!curRect) {
4683 /* In drawable flag is set below */
4685 if (This->render_offscreen) {
4686 glScissor(This->stateBlock->viewport.X,
4687 This->stateBlock->viewport.Y,
4688 This->stateBlock->viewport.Width,
4689 This->stateBlock->viewport.Height);
4690 } else {
4691 glScissor(This->stateBlock->viewport.X,
4692 (((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height -
4693 (This->stateBlock->viewport.Y + This->stateBlock->viewport.Height)),
4694 This->stateBlock->viewport.Width,
4695 This->stateBlock->viewport.Height);
4697 checkGLcall("glScissor");
4698 glClear(glMask);
4699 checkGLcall("glClear");
4700 } else {
4701 if(!(target->Flags & SFLAG_INDRAWABLE) &&
4702 !(wined3d_settings.offscreen_rendering_mode == ORM_FBO && This->render_offscreen && target->Flags & SFLAG_INTEXTURE)) {
4704 if(curRect[0].x1 > 0 || curRect[0].y1 > 0 ||
4705 curRect[0].x2 < target->currentDesc.Width ||
4706 curRect[0].y2 < target->currentDesc.Height) {
4707 TRACE("Partial clear, and surface not in drawable. Blitting texture to drawable\n");
4708 blt_to_drawable(This, target);
4712 /* Now process each rect in turn */
4713 for (i = 0; i < Count; i++) {
4714 /* Note gl uses lower left, width/height */
4715 TRACE("(%p) %p Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This, curRect,
4716 curRect[i].x1, curRect[i].y1, curRect[i].x2, curRect[i].y2,
4717 curRect[i].x1, (target->currentDesc.Height - curRect[i].y2),
4718 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4720 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4721 * The rectangle is not cleared, no error is returned, but further rectanlges are
4722 * still cleared if they are valid
4724 if(curRect[i].x1 > curRect[i].x2 || curRect[i].y1 > curRect[i].y2) {
4725 TRACE("Rectangle with negative dimensions, ignoring\n");
4726 continue;
4729 if(This->render_offscreen) {
4730 glScissor(curRect[i].x1, curRect[i].y1,
4731 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4732 } else {
4733 glScissor(curRect[i].x1, target->currentDesc.Height - curRect[i].y2,
4734 curRect[i].x2 - curRect[i].x1, curRect[i].y2 - curRect[i].y1);
4736 checkGLcall("glScissor");
4738 glClear(glMask);
4739 checkGLcall("glClear");
4743 /* Restore the old values (why..?) */
4744 if (Flags & WINED3DCLEAR_STENCIL) {
4745 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4747 if (Flags & WINED3DCLEAR_TARGET) {
4748 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4749 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4750 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4751 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4752 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4755 LEAVE_GL();
4757 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4758 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4760 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4761 target->Flags |= SFLAG_INTEXTURE;
4762 target->Flags &= ~SFLAG_INSYSMEM;
4763 } else {
4764 target->Flags |= SFLAG_INDRAWABLE;
4765 target->Flags &= ~(SFLAG_INTEXTURE | SFLAG_INSYSMEM);
4767 return WINED3D_OK;
4770 /*****
4771 * Drawing functions
4772 *****/
4773 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4774 UINT PrimitiveCount) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4779 debug_d3dprimitivetype(PrimitiveType),
4780 StartVertex, PrimitiveCount);
4782 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4783 if(This->stateBlock->streamIsUP) {
4784 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4785 This->stateBlock->streamIsUP = FALSE;
4788 if(This->stateBlock->loadBaseVertexIndex != 0) {
4789 This->stateBlock->loadBaseVertexIndex = 0;
4790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4792 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4793 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4794 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4795 return WINED3D_OK;
4798 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4799 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4800 WINED3DPRIMITIVETYPE PrimitiveType,
4801 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4804 UINT idxStride = 2;
4805 IWineD3DIndexBuffer *pIB;
4806 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4807 GLuint vbo;
4809 pIB = This->stateBlock->pIndexData;
4810 if (!pIB) {
4811 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
4812 * without an index buffer set. (The first time at least...)
4813 * D3D8 simply dies, but I doubt it can do much harm to return
4814 * D3DERR_INVALIDCALL there as well. */
4815 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
4816 return WINED3DERR_INVALIDCALL;
4819 if(This->stateBlock->streamIsUP) {
4820 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4821 This->stateBlock->streamIsUP = FALSE;
4823 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
4825 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
4826 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4827 minIndex, NumVertices, startIndex, primCount);
4829 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
4830 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
4831 idxStride = 2;
4832 } else {
4833 idxStride = 4;
4836 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
4837 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
4838 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4841 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
4842 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
4844 return WINED3D_OK;
4847 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4848 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
4849 UINT VertexStreamZeroStride) {
4850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4851 IWineD3DVertexBuffer *vb;
4853 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
4854 debug_d3dprimitivetype(PrimitiveType),
4855 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
4857 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4858 vb = This->stateBlock->streamSource[0];
4859 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4860 if(vb) IWineD3DVertexBuffer_Release(vb);
4861 This->stateBlock->streamOffset[0] = 0;
4862 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4863 This->stateBlock->streamIsUP = TRUE;
4864 This->stateBlock->loadBaseVertexIndex = 0;
4866 /* TODO: Only mark dirty if drawing from a different UP address */
4867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4869 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
4870 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
4872 /* MSDN specifies stream zero settings must be set to NULL */
4873 This->stateBlock->streamStride[0] = 0;
4874 This->stateBlock->streamSource[0] = NULL;
4876 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
4877 * the new stream sources or use UP drawing again
4879 return WINED3D_OK;
4882 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
4883 UINT MinVertexIndex, UINT NumVertices,
4884 UINT PrimitiveCount, CONST void* pIndexData,
4885 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
4886 UINT VertexStreamZeroStride) {
4887 int idxStride;
4888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4889 IWineD3DVertexBuffer *vb;
4890 IWineD3DIndexBuffer *ib;
4892 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
4893 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
4894 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
4895 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
4897 if (IndexDataFormat == WINED3DFMT_INDEX16) {
4898 idxStride = 2;
4899 } else {
4900 idxStride = 4;
4903 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
4904 vb = This->stateBlock->streamSource[0];
4905 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
4906 if(vb) IWineD3DVertexBuffer_Release(vb);
4907 This->stateBlock->streamIsUP = TRUE;
4908 This->stateBlock->streamOffset[0] = 0;
4909 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
4911 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
4912 This->stateBlock->baseVertexIndex = 0;
4913 This->stateBlock->loadBaseVertexIndex = 0;
4914 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
4915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4916 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4918 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
4920 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
4921 This->stateBlock->streamSource[0] = NULL;
4922 This->stateBlock->streamStride[0] = 0;
4923 ib = This->stateBlock->pIndexData;
4924 if(ib) {
4925 IWineD3DIndexBuffer_Release(ib);
4926 This->stateBlock->pIndexData = NULL;
4928 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
4929 * SetStreamSource to specify a vertex buffer
4932 return WINED3D_OK;
4935 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
4936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4938 /* Mark the state dirty until we have nicer tracking
4939 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4940 * that value.
4942 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4943 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4944 This->stateBlock->baseVertexIndex = 0;
4945 This->up_strided = DrawPrimStrideData;
4946 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
4947 This->up_strided = NULL;
4948 return WINED3D_OK;
4951 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
4952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
4953 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
4955 /* Mark the state dirty until we have nicer tracking
4956 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
4957 * that value.
4959 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
4960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4961 This->stateBlock->streamIsUP = TRUE;
4962 This->stateBlock->baseVertexIndex = 0;
4963 This->up_strided = DrawPrimStrideData;
4964 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
4965 This->up_strided = NULL;
4966 return WINED3D_OK;
4970 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
4971 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 HRESULT hr = WINED3D_OK;
4974 WINED3DRESOURCETYPE sourceType;
4975 WINED3DRESOURCETYPE destinationType;
4976 int i ,levels;
4978 /* TODO: think about moving the code into IWineD3DBaseTexture */
4980 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
4982 /* verify that the source and destination textures aren't NULL */
4983 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
4984 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
4985 This, pSourceTexture, pDestinationTexture);
4986 hr = WINED3DERR_INVALIDCALL;
4989 if (pSourceTexture == pDestinationTexture) {
4990 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
4991 This, pSourceTexture, pDestinationTexture);
4992 hr = WINED3DERR_INVALIDCALL;
4994 /* Verify that the source and destination textures are the same type */
4995 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
4996 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
4998 if (sourceType != destinationType) {
4999 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5000 This);
5001 hr = WINED3DERR_INVALIDCALL;
5004 /* check that both textures have the identical numbers of levels */
5005 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5006 WARN("(%p) : source (%p) and destination (%p) textures must have identicle numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5007 hr = WINED3DERR_INVALIDCALL;
5010 if (WINED3D_OK == hr) {
5012 /* Make sure that the destination texture is loaded */
5013 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5015 /* Update every surface level of the texture */
5016 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5018 switch (sourceType) {
5019 case WINED3DRTYPE_TEXTURE:
5021 IWineD3DSurface *srcSurface;
5022 IWineD3DSurface *destSurface;
5024 for (i = 0 ; i < levels ; ++i) {
5025 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5026 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5027 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5028 IWineD3DSurface_Release(srcSurface);
5029 IWineD3DSurface_Release(destSurface);
5030 if (WINED3D_OK != hr) {
5031 WARN("(%p) : Call to update surface failed\n", This);
5032 return hr;
5036 break;
5037 case WINED3DRTYPE_CUBETEXTURE:
5039 IWineD3DSurface *srcSurface;
5040 IWineD3DSurface *destSurface;
5041 WINED3DCUBEMAP_FACES faceType;
5043 for (i = 0 ; i < levels ; ++i) {
5044 /* Update each cube face */
5045 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5046 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5047 if (WINED3D_OK != hr) {
5048 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5049 } else {
5050 TRACE("Got srcSurface %p\n", srcSurface);
5052 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5053 if (WINED3D_OK != hr) {
5054 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5055 } else {
5056 TRACE("Got desrSurface %p\n", destSurface);
5058 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5059 IWineD3DSurface_Release(srcSurface);
5060 IWineD3DSurface_Release(destSurface);
5061 if (WINED3D_OK != hr) {
5062 WARN("(%p) : Call to update surface failed\n", This);
5063 return hr;
5068 break;
5069 #if 0 /* TODO: Add support for volume textures */
5070 case WINED3DRTYPE_VOLUMETEXTURE:
5072 IWineD3DVolume srcVolume = NULL;
5073 IWineD3DSurface destVolume = NULL;
5075 for (i = 0 ; i < levels ; ++i) {
5076 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5077 IWineD3DVolumeTexture_GetVolume((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5078 hr = IWineD3DFoo_UpdateVolume(iface, srcVolume, NULL, destVolume, NULL);
5079 IWineD3DVolume_Release(srcSurface);
5080 IWineD3DVolume_Release(destSurface);
5081 if (WINED3D_OK != hr) {
5082 WARN("(%p) : Call to update volume failed\n", This);
5083 return hr;
5087 break;
5088 #endif
5089 default:
5090 FIXME("(%p) : Unsupported source and destination type\n", This);
5091 hr = WINED3DERR_INVALIDCALL;
5095 return hr;
5098 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5099 IWineD3DSwapChain *swapChain;
5100 HRESULT hr;
5101 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5102 if(hr == WINED3D_OK) {
5103 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5104 IWineD3DSwapChain_Release(swapChain);
5106 return hr;
5109 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5111 /* return a sensible default */
5112 *pNumPasses = 1;
5113 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5114 FIXME("(%p) : stub\n", This);
5115 return WINED3D_OK;
5118 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5120 int j;
5121 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5122 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5123 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5124 return WINED3DERR_INVALIDCALL;
5126 for (j = 0; j < 256; ++j) {
5127 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5128 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5129 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5130 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5132 TRACE("(%p) : returning\n", This);
5133 return WINED3D_OK;
5136 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 int j;
5139 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5140 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5141 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5142 return WINED3DERR_INVALIDCALL;
5144 for (j = 0; j < 256; ++j) {
5145 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5146 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5147 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5148 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5150 TRACE("(%p) : returning\n", This);
5151 return WINED3D_OK;
5154 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5156 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5157 if ( PaletteNumber < 0 || PaletteNumber >= MAX_PALETTES) {
5158 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5159 return WINED3DERR_INVALIDCALL;
5161 /*TODO: stateblocks */
5162 This->currentPalette = PaletteNumber;
5163 TRACE("(%p) : returning\n", This);
5164 return WINED3D_OK;
5167 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5169 if (PaletteNumber == NULL) {
5170 WARN("(%p) : returning Invalid Call\n", This);
5171 return WINED3DERR_INVALIDCALL;
5173 /*TODO: stateblocks */
5174 *PaletteNumber = This->currentPalette;
5175 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5176 return WINED3D_OK;
5179 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 static BOOL showFixmes = TRUE;
5182 if (showFixmes) {
5183 FIXME("(%p) : stub\n", This);
5184 showFixmes = FALSE;
5187 This->softwareVertexProcessing = bSoftware;
5188 return WINED3D_OK;
5192 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5194 static BOOL showFixmes = TRUE;
5195 if (showFixmes) {
5196 FIXME("(%p) : stub\n", This);
5197 showFixmes = FALSE;
5199 return This->softwareVertexProcessing;
5203 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 IWineD3DSwapChain *swapChain;
5206 HRESULT hr;
5208 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5210 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, (IWineD3DSwapChain **)&swapChain);
5211 if(hr == WINED3D_OK){
5212 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5213 IWineD3DSwapChain_Release(swapChain);
5214 }else{
5215 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5217 return hr;
5221 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5223 static BOOL showfixmes = TRUE;
5224 if(nSegments != 0.0f) {
5225 if( showfixmes) {
5226 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5227 showfixmes = FALSE;
5230 return WINED3D_OK;
5233 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 static BOOL showfixmes = TRUE;
5236 if( showfixmes) {
5237 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5238 showfixmes = FALSE;
5240 return 0.0f;
5243 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5245 /** TODO: remove casts to IWineD3DSurfaceImpl
5246 * NOTE: move code to surface to accomplish this
5247 ****************************************/
5248 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5249 int srcWidth, srcHeight;
5250 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5251 WINED3DFORMAT destFormat, srcFormat;
5252 UINT destSize;
5253 int srcLeft, destLeft, destTop;
5254 WINED3DPOOL srcPool, destPool;
5255 int offset = 0;
5256 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5257 glDescriptor *glDescription = NULL;
5258 GLenum dummy;
5259 int bpp;
5260 CONVERT_TYPES convert = NO_CONVERSION;
5262 WINED3DSURFACE_DESC winedesc;
5264 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5265 memset(&winedesc, 0, sizeof(winedesc));
5266 winedesc.Width = &srcSurfaceWidth;
5267 winedesc.Height = &srcSurfaceHeight;
5268 winedesc.Pool = &srcPool;
5269 winedesc.Format = &srcFormat;
5271 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5273 winedesc.Width = &destSurfaceWidth;
5274 winedesc.Height = &destSurfaceHeight;
5275 winedesc.Pool = &destPool;
5276 winedesc.Format = &destFormat;
5277 winedesc.Size = &destSize;
5279 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5281 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5282 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5283 return WINED3DERR_INVALIDCALL;
5286 /* This call loads the opengl surface directly, instead of copying the surface to the
5287 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5288 * copy in sysmem and use regular surface loading.
5290 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5291 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5292 if(convert != NO_CONVERSION) {
5293 return IWineD3DSurface_BltFast(pDestinationSurface,
5294 pDestPoint ? pDestPoint->x : 0,
5295 pDestPoint ? pDestPoint->y : 0,
5296 pSourceSurface, (RECT *) pSourceRect, 0);
5299 if (destFormat == WINED3DFMT_UNKNOWN) {
5300 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5301 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5303 /* Get the update surface description */
5304 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5307 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5309 ENTER_GL();
5311 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5312 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5313 checkGLcall("glActiveTextureARB");
5316 /* Make sure the surface is loaded and up to date */
5317 IWineD3DSurface_PreLoad(pDestinationSurface);
5319 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5321 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5322 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5323 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5324 srcLeft = pSourceRect ? pSourceRect->left : 0;
5325 destLeft = pDestPoint ? pDestPoint->x : 0;
5326 destTop = pDestPoint ? pDestPoint->y : 0;
5329 /* This function doesn't support compressed textures
5330 the pitch is just bytesPerPixel * width */
5331 if(srcWidth != srcSurfaceWidth || srcLeft ){
5332 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5333 offset += srcLeft * pSrcSurface->bytesPerPixel;
5334 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5336 /* TODO DXT formats */
5338 if(pSourceRect != NULL && pSourceRect->top != 0){
5339 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5341 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5342 ,This
5343 ,glDescription->level
5344 ,destLeft
5345 ,destTop
5346 ,srcWidth
5347 ,srcHeight
5348 ,glDescription->glFormat
5349 ,glDescription->glType
5350 ,IWineD3DSurface_GetData(pSourceSurface)
5353 /* Sanity check */
5354 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5356 /* need to lock the surface to get the data */
5357 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5360 /* TODO: Cube and volume support */
5361 if(rowoffset != 0){
5362 /* not a whole row so we have to do it a line at a time */
5363 int j;
5365 /* hopefully using pointer addtion will be quicker than using a point + j * rowoffset */
5366 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5368 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5370 glTexSubImage2D(glDescription->target
5371 ,glDescription->level
5372 ,destLeft
5374 ,srcWidth
5376 ,glDescription->glFormat
5377 ,glDescription->glType
5378 ,data /* could be quicker using */
5380 data += rowoffset;
5383 } else { /* Full width, so just write out the whole texture */
5385 if (WINED3DFMT_DXT1 == destFormat ||
5386 WINED3DFMT_DXT2 == destFormat ||
5387 WINED3DFMT_DXT3 == destFormat ||
5388 WINED3DFMT_DXT4 == destFormat ||
5389 WINED3DFMT_DXT5 == destFormat) {
5390 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5391 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5392 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5393 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5394 } if (destFormat != srcFormat) {
5395 FIXME("Updating mixed format compressed texture is not curretly support\n");
5396 } else {
5397 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5398 glDescription->level,
5399 glDescription->glFormatInternal,
5400 srcWidth,
5401 srcHeight,
5403 destSize,
5404 IWineD3DSurface_GetData(pSourceSurface));
5406 } else {
5407 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5411 } else {
5412 glTexSubImage2D(glDescription->target
5413 ,glDescription->level
5414 ,destLeft
5415 ,destTop
5416 ,srcWidth
5417 ,srcHeight
5418 ,glDescription->glFormat
5419 ,glDescription->glType
5420 ,IWineD3DSurface_GetData(pSourceSurface)
5424 checkGLcall("glTexSubImage2D");
5426 LEAVE_GL();
5428 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags &= ~SFLAG_INSYSMEM;
5429 ((IWineD3DSurfaceImpl *)pDestinationSurface)->Flags |= SFLAG_INTEXTURE;
5430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5432 return WINED3D_OK;
5435 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5437 struct WineD3DRectPatch *patch;
5438 unsigned int i;
5439 struct list *e;
5440 BOOL found;
5441 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5443 if(!(Handle || pRectPatchInfo)) {
5444 /* TODO: Write a test for the return value, thus the FIXME */
5445 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5446 return WINED3DERR_INVALIDCALL;
5449 if(Handle) {
5450 i = PATCHMAP_HASHFUNC(Handle);
5451 found = FALSE;
5452 LIST_FOR_EACH(e, &This->patches[i]) {
5453 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5454 if(patch->Handle == Handle) {
5455 found = TRUE;
5456 break;
5460 if(!found) {
5461 TRACE("Patch does not exist. Creating a new one\n");
5462 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5463 patch->Handle = Handle;
5464 list_add_head(&This->patches[i], &patch->entry);
5465 } else {
5466 TRACE("Found existing patch %p\n", patch);
5468 } else {
5469 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5470 * attributes we have to tesselate, read back, and draw. This needs a patch
5471 * management structure instance. Create one.
5473 * A possible improvement is to check if a vertex shader is used, and if not directly
5474 * draw the patch.
5476 FIXME("Drawing an uncached patch. This is slow\n");
5477 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5480 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5481 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5482 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5483 HRESULT hr;
5484 TRACE("Tesselation density or patch info changed, retesselating\n");
5486 if(pRectPatchInfo) {
5487 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5489 patch->numSegs[0] = pNumSegs[0];
5490 patch->numSegs[1] = pNumSegs[1];
5491 patch->numSegs[2] = pNumSegs[2];
5492 patch->numSegs[3] = pNumSegs[3];
5494 hr = tesselate_rectpatch(This, patch);
5495 if(FAILED(hr)) {
5496 WARN("Patch tesselation failed\n");
5498 /* Do not release the handle to store the params of the patch */
5499 if(!Handle) {
5500 HeapFree(GetProcessHeap(), 0, patch);
5502 return hr;
5506 This->currentPatch = patch;
5507 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5508 This->currentPatch = NULL;
5510 /* Destroy uncached patches */
5511 if(!Handle) {
5512 HeapFree(GetProcessHeap(), 0, patch->mem);
5513 HeapFree(GetProcessHeap(), 0, patch);
5515 return WINED3D_OK;
5518 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5519 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5521 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5522 FIXME("(%p) : Stub\n", This);
5523 return WINED3D_OK;
5526 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 int i;
5529 struct WineD3DRectPatch *patch;
5530 struct list *e;
5531 TRACE("(%p) Handle(%d)\n", This, Handle);
5533 i = PATCHMAP_HASHFUNC(Handle);
5534 LIST_FOR_EACH(e, &This->patches[i]) {
5535 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5536 if(patch->Handle == Handle) {
5537 TRACE("Deleting patch %p\n", patch);
5538 list_remove(&patch->entry);
5539 HeapFree(GetProcessHeap(), 0, patch->mem);
5540 HeapFree(GetProcessHeap(), 0, patch);
5541 return WINED3D_OK;
5545 /* TODO: Write a test for the return value */
5546 FIXME("Attempt to destroy nonexistant patch\n");
5547 return WINED3DERR_INVALIDCALL;
5550 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5551 HRESULT hr;
5552 IWineD3DSwapChain *swapchain;
5554 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5555 if (SUCCEEDED(hr)) {
5556 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5557 return swapchain;
5560 return NULL;
5563 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5566 if (!*fbo) {
5567 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5568 checkGLcall("glGenFramebuffersEXT()");
5570 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5571 checkGLcall("glBindFramebuffer()");
5574 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5575 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5576 IWineD3DBaseTextureImpl *texture_impl;
5577 GLenum texttarget, target;
5578 GLint old_binding;
5580 texttarget = surface_impl->glDescription.target;
5581 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5582 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5584 IWineD3DSurface_PreLoad(surface);
5586 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5587 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5588 glBindTexture(target, old_binding);
5590 /* Update base texture states array */
5591 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5592 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5593 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5594 if (texture_impl->baseTexture.bindCount) {
5595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5598 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5601 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5602 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5604 checkGLcall("attach_surface_fbo");
5607 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5609 IWineD3DSwapChain *swapchain;
5611 swapchain = get_swapchain(surface);
5612 if (swapchain) {
5613 GLenum buffer;
5615 TRACE("Surface %p is onscreen\n", surface);
5617 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5618 buffer = surface_get_gl_buffer(surface, swapchain);
5619 glDrawBuffer(buffer);
5620 checkGLcall("glDrawBuffer()");
5621 } else {
5622 TRACE("Surface %p is offscreen\n", surface);
5623 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5624 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5627 if (rect) {
5628 glEnable(GL_SCISSOR_TEST);
5629 if(!swapchain) {
5630 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5631 } else {
5632 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5633 rect->x2 - rect->x1, rect->y2 - rect->y1);
5635 checkGLcall("glScissor");
5636 } else {
5637 glDisable(GL_SCISSOR_TEST);
5639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5641 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5644 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5645 glClear(GL_COLOR_BUFFER_BIT);
5646 checkGLcall("glClear");
5648 if (This->render_offscreen) {
5649 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5650 } else {
5651 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5652 checkGLcall("glBindFramebuffer()");
5655 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5656 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5657 glDrawBuffer(GL_BACK);
5658 checkGLcall("glDrawBuffer()");
5662 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5664 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
5665 WINEDDBLTFX BltFx;
5666 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
5668 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
5669 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
5670 return WINED3DERR_INVALIDCALL;
5673 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5674 color_fill_fbo(iface, pSurface, pRect, color);
5675 return WINED3D_OK;
5676 } else {
5677 /* Just forward this to the DirectDraw blitting engine */
5678 memset(&BltFx, 0, sizeof(BltFx));
5679 BltFx.dwSize = sizeof(BltFx);
5680 BltFx.u5.dwFillColor = color;
5681 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
5685 /* rendertarget and deptth stencil functions */
5686 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
5687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
5690 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
5691 return WINED3DERR_INVALIDCALL;
5694 *ppRenderTarget = This->render_targets[RenderTargetIndex];
5695 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
5696 /* Note inc ref on returned surface */
5697 if(*ppRenderTarget != NULL)
5698 IWineD3DSurface_AddRef(*ppRenderTarget);
5699 return WINED3D_OK;
5702 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
5703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5704 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
5705 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
5706 IWineD3DSwapChainImpl *Swapchain;
5707 HRESULT hr;
5709 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
5711 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
5712 if(hr != WINED3D_OK) {
5713 ERR("Can't get the swapchain\n");
5714 return hr;
5717 /* Make sure to release the swapchain */
5718 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
5720 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
5721 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5722 return WINED3DERR_INVALIDCALL;
5724 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
5725 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
5726 return WINED3DERR_INVALIDCALL;
5729 if(Swapchain->frontBuffer != Front) {
5730 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
5732 if(Swapchain->frontBuffer)
5733 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
5734 Swapchain->frontBuffer = Front;
5736 if(Swapchain->frontBuffer) {
5737 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
5741 if(Back && !Swapchain->backBuffer) {
5742 /* We need memory for the back buffer array - only one back buffer this way */
5743 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
5744 if(!Swapchain->backBuffer) {
5745 ERR("Out of memory\n");
5746 return E_OUTOFMEMORY;
5750 if(Swapchain->backBuffer[0] != Back) {
5751 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
5753 /* What to do about the context here in the case of multithreading? Not sure.
5754 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
5756 ENTER_GL();
5757 if(!Swapchain->backBuffer[0]) {
5758 /* GL was told to draw to the front buffer at creation,
5759 * undo that
5761 glDrawBuffer(GL_BACK);
5762 checkGLcall("glDrawBuffer(GL_BACK)");
5763 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
5764 Swapchain->presentParms.BackBufferCount = 1;
5765 } else if (!Back) {
5766 /* That makes problems - disable for now */
5767 /* glDrawBuffer(GL_FRONT); */
5768 checkGLcall("glDrawBuffer(GL_FRONT)");
5769 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
5770 Swapchain->presentParms.BackBufferCount = 0;
5772 LEAVE_GL();
5774 if(Swapchain->backBuffer[0])
5775 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
5776 Swapchain->backBuffer[0] = Back;
5778 if(Swapchain->backBuffer[0]) {
5779 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
5780 } else {
5781 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
5786 return WINED3D_OK;
5789 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
5790 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5791 *ppZStencilSurface = This->depthStencilBuffer;
5792 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
5794 if(*ppZStencilSurface != NULL) {
5795 /* Note inc ref on returned surface */
5796 IWineD3DSurface_AddRef(*ppZStencilSurface);
5798 return WINED3D_OK;
5801 /* TODO: Handle stencil attachments */
5802 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
5803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5804 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
5806 TRACE("Set depth stencil to %p\n", depth_stencil);
5808 if (depth_stencil_impl) {
5809 if (depth_stencil_impl->current_renderbuffer) {
5810 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
5811 checkGLcall("glFramebufferRenderbufferEXT()");
5812 } else {
5813 IWineD3DBaseTextureImpl *texture_impl;
5814 GLenum texttarget, target;
5815 GLint old_binding = 0;
5817 texttarget = depth_stencil_impl->glDescription.target;
5818 target = texttarget == GL_TEXTURE_2D ? GL_TEXTURE_2D : GL_TEXTURE_CUBE_MAP_ARB;
5819 glGetIntegerv(texttarget == GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D : GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5821 IWineD3DSurface_PreLoad(depth_stencil);
5823 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5824 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5825 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
5826 glBindTexture(target, old_binding);
5828 /* Update base texture states array */
5829 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5830 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5831 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5832 if (texture_impl->baseTexture.bindCount) {
5833 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5836 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5839 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
5840 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
5841 checkGLcall("glFramebufferTexture2DEXT()");
5843 } else {
5844 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
5845 checkGLcall("glFramebufferTexture2DEXT()");
5849 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
5850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5851 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
5853 TRACE("Set render target %u to %p\n", idx, render_target);
5855 if (rtimpl) {
5856 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
5857 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
5858 } else {
5859 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
5860 checkGLcall("glFramebufferTexture2DEXT()");
5862 This->draw_buffers[idx] = GL_NONE;
5866 static void check_fbo_status(IWineD3DDevice *iface) {
5867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5868 GLenum status;
5870 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
5871 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
5872 TRACE("FBO complete\n");
5873 } else {
5874 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
5876 /* Dump the FBO attachments */
5877 if (status == GL_FRAMEBUFFER_UNSUPPORTED_EXT) {
5878 IWineD3DSurfaceImpl *attachment;
5879 int i;
5881 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5882 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
5883 if (attachment) {
5884 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
5885 attachment->pow2Width, attachment->pow2Height);
5888 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
5889 if (attachment) {
5890 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
5891 attachment->pow2Width, attachment->pow2Height);
5897 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
5898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
5900 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
5902 if (!ds_impl) return FALSE;
5904 if (ds_impl->current_renderbuffer) {
5905 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
5906 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
5909 return (rt_impl->pow2Width != ds_impl->pow2Width ||
5910 rt_impl->pow2Height != ds_impl->pow2Height);
5913 void apply_fbo_state(IWineD3DDevice *iface) {
5914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5915 unsigned int i;
5917 if (This->render_offscreen) {
5918 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5920 /* Apply render targets */
5921 for (i = 0; i < GL_LIMITS(buffers); ++i) {
5922 IWineD3DSurface *render_target = This->render_targets[i];
5923 if (This->fbo_color_attachments[i] != render_target) {
5924 set_render_target_fbo(iface, i, render_target);
5925 This->fbo_color_attachments[i] = render_target;
5929 /* Apply depth targets */
5930 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
5931 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
5932 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
5934 if (This->stencilBufferTarget) {
5935 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
5937 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
5938 This->fbo_depth_attachment = This->stencilBufferTarget;
5941 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
5942 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
5943 checkGLcall("glDrawBuffers()");
5944 } else {
5945 glDrawBuffer(This->draw_buffers[0]);
5946 checkGLcall("glDrawBuffer()");
5948 } else {
5949 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5952 check_fbo_status(iface);
5955 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
5956 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
5957 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5958 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
5959 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
5960 GLenum gl_filter;
5962 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
5963 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
5964 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
5965 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
5967 switch (filter) {
5968 case WINED3DTEXF_LINEAR:
5969 gl_filter = GL_LINEAR;
5970 break;
5972 default:
5973 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
5974 case WINED3DTEXF_NONE:
5975 case WINED3DTEXF_POINT:
5976 gl_filter = GL_NEAREST;
5977 break;
5980 /* Attach src surface to src fbo */
5981 src_swapchain = get_swapchain(src_surface);
5982 if (src_swapchain) {
5983 GLenum buffer;
5985 TRACE("Source surface %p is onscreen\n", src_surface);
5986 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
5988 ENTER_GL();
5989 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
5990 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
5991 glReadBuffer(buffer);
5992 checkGLcall("glReadBuffer()");
5994 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
5995 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
5996 } else {
5997 TRACE("Source surface %p is offscreen\n", src_surface);
5998 ENTER_GL();
5999 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6000 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6001 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6002 checkGLcall("glReadBuffer()");
6004 LEAVE_GL();
6006 /* Attach dst surface to dst fbo */
6007 dst_swapchain = get_swapchain(dst_surface);
6008 if (dst_swapchain) {
6009 GLenum buffer;
6011 TRACE("Destination surface %p is onscreen\n", dst_surface);
6012 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6014 ENTER_GL();
6015 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6016 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6017 glDrawBuffer(buffer);
6018 checkGLcall("glDrawBuffer()");
6020 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6021 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6022 } else {
6023 TRACE("Destination surface %p is offscreen\n", dst_surface);
6025 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6026 if(!src_swapchain) {
6027 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6030 ENTER_GL();
6031 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6032 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6033 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6034 checkGLcall("glDrawBuffer()");
6036 glDisable(GL_SCISSOR_TEST);
6037 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6039 if (flip) {
6040 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6041 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6042 checkGLcall("glBlitFramebuffer()");
6043 } else {
6044 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6045 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6046 checkGLcall("glBlitFramebuffer()");
6049 if (This->render_offscreen) {
6050 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6051 } else {
6052 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6053 checkGLcall("glBindFramebuffer()");
6056 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6057 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6058 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6059 glDrawBuffer(GL_BACK);
6060 checkGLcall("glDrawBuffer()");
6062 LEAVE_GL();
6065 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6067 WINED3DVIEWPORT viewport;
6069 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6071 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6072 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6073 return WINED3DERR_INVALIDCALL;
6076 /* MSDN says that null disables the render target
6077 but a device must always be associated with a render target
6078 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6080 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6081 for more details
6083 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6084 FIXME("Trying to set render target 0 to NULL\n");
6085 return WINED3DERR_INVALIDCALL;
6087 if (pRenderTarget && !((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET) {
6088 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);
6089 return WINED3DERR_INVALIDCALL;
6092 /* If we are trying to set what we already have, don't bother */
6093 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6094 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6095 return WINED3D_OK;
6097 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6098 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6099 This->render_targets[RenderTargetIndex] = pRenderTarget;
6101 /* Render target 0 is special */
6102 if(RenderTargetIndex == 0) {
6103 /* Finally, reset the viewport as the MSDN states. */
6104 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6105 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6106 viewport.X = 0;
6107 viewport.Y = 0;
6108 viewport.MaxZ = 1.0f;
6109 viewport.MinZ = 0.0f;
6110 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6111 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6112 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6114 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6116 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6117 * ctx properly.
6118 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6119 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6121 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6123 return WINED3D_OK;
6126 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 HRESULT hr = WINED3D_OK;
6129 IWineD3DSurface *tmp;
6131 TRACE("(%p) Swapping z-buffer\n",This);
6133 if (pNewZStencil == This->stencilBufferTarget) {
6134 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6135 } else {
6136 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incure an extra memory overhead
6137 * depending on the renter target implementation being used.
6138 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6139 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6140 * stencil buffer and incure an extra memory overhead
6141 ******************************************************/
6143 tmp = This->stencilBufferTarget;
6144 This->stencilBufferTarget = pNewZStencil;
6145 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6146 /* should we be calling the parent or the wined3d surface? */
6147 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6148 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6149 hr = WINED3D_OK;
6151 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6152 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6153 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6155 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6159 return hr;
6162 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6163 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6165 /* TODO: the use of Impl is deprecated. */
6166 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6167 WINED3DLOCKED_RECT lockedRect;
6169 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6171 /* some basic validation checks */
6172 if(This->cursorTexture) {
6173 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6174 ENTER_GL();
6175 glDeleteTextures(1, &This->cursorTexture);
6176 LEAVE_GL();
6177 This->cursorTexture = 0;
6180 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6181 This->haveHardwareCursor = TRUE;
6182 else
6183 This->haveHardwareCursor = FALSE;
6185 if(pCursorBitmap) {
6186 WINED3DLOCKED_RECT rect;
6188 /* MSDN: Cursor must be A8R8G8B8 */
6189 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6190 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6191 return WINED3DERR_INVALIDCALL;
6194 /* MSDN: Cursor must be smaller than the display mode */
6195 if(pSur->currentDesc.Width > This->ddraw_width ||
6196 pSur->currentDesc.Height > This->ddraw_height) {
6197 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);
6198 return WINED3DERR_INVALIDCALL;
6201 if (!This->haveHardwareCursor) {
6202 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6204 /* Do not store the surface's pointer because the application may
6205 * release it after setting the cursor image. Windows doesn't
6206 * addref the set surface, so we can't do this either without
6207 * creating circular refcount dependencies. Copy out the gl texture
6208 * instead.
6210 This->cursorWidth = pSur->currentDesc.Width;
6211 This->cursorHeight = pSur->currentDesc.Height;
6212 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6214 const GlPixelFormatDesc *glDesc;
6215 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6216 char *mem, *bits = (char *)rect.pBits;
6217 GLint intfmt = glDesc->glInternal;
6218 GLint format = glDesc->glFormat;
6219 GLint type = glDesc->glType;
6220 INT height = This->cursorHeight;
6221 INT width = This->cursorWidth;
6222 INT bpp = tableEntry->bpp;
6223 INT i;
6225 /* Reformat the texture memory (pitch and width can be
6226 * different) */
6227 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6228 for(i = 0; i < height; i++)
6229 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6230 IWineD3DSurface_UnlockRect(pCursorBitmap);
6231 ENTER_GL();
6233 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6234 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6235 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6238 /* Make sure that a proper texture unit is selected */
6239 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6240 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6241 checkGLcall("glActiveTextureARB");
6243 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6244 /* Create a new cursor texture */
6245 glGenTextures(1, &This->cursorTexture);
6246 checkGLcall("glGenTextures");
6247 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6248 checkGLcall("glBindTexture");
6249 /* Copy the bitmap memory into the cursor texture */
6250 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6251 HeapFree(GetProcessHeap(), 0, mem);
6252 checkGLcall("glTexImage2D");
6254 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6255 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6256 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6259 LEAVE_GL();
6261 else
6263 FIXME("A cursor texture was not returned.\n");
6264 This->cursorTexture = 0;
6267 else
6269 /* Draw a hardware cursor */
6270 ICONINFO cursorInfo;
6271 HCURSOR cursor;
6272 /* Create and clear maskBits because it is not needed for
6273 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6274 * chunks. */
6275 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6276 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6277 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6278 WINED3DLOCK_NO_DIRTY_UPDATE |
6279 WINED3DLOCK_READONLY
6281 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6282 pSur->currentDesc.Height);
6284 cursorInfo.fIcon = FALSE;
6285 cursorInfo.xHotspot = XHotSpot;
6286 cursorInfo.yHotspot = YHotSpot;
6287 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6288 pSur->currentDesc.Height, 1,
6289 1, &maskBits);
6290 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6291 pSur->currentDesc.Height, 1,
6292 32, lockedRect.pBits);
6293 IWineD3DSurface_UnlockRect(pCursorBitmap);
6294 /* Create our cursor and clean up. */
6295 cursor = CreateIconIndirect(&cursorInfo);
6296 SetCursor(cursor);
6297 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6298 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6299 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6300 This->hardwareCursor = cursor;
6301 HeapFree(GetProcessHeap(), 0, maskBits);
6305 This->xHotSpot = XHotSpot;
6306 This->yHotSpot = YHotSpot;
6307 return WINED3D_OK;
6310 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6312 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6314 This->xScreenSpace = XScreenSpace;
6315 This->yScreenSpace = YScreenSpace;
6317 return;
6321 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6323 BOOL oldVisible = This->bCursorVisible;
6324 POINT pt;
6326 TRACE("(%p) : visible(%d)\n", This, bShow);
6329 * When ShowCursor is first called it should make the cursor appear at the OS's last
6330 * known cursor position. Because of this, some applications just repetitively call
6331 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6333 GetCursorPos(&pt);
6334 This->xScreenSpace = pt.x;
6335 This->yScreenSpace = pt.y;
6337 if (This->haveHardwareCursor) {
6338 This->bCursorVisible = bShow;
6339 if (bShow)
6340 SetCursor(This->hardwareCursor);
6341 else
6342 SetCursor(NULL);
6344 else
6346 if (This->cursorTexture)
6347 This->bCursorVisible = bShow;
6350 return oldVisible;
6353 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6355 TRACE("(%p) : state (%u)\n", This, This->state);
6356 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6357 switch (This->state) {
6358 case WINED3D_OK:
6359 return WINED3D_OK;
6360 case WINED3DERR_DEVICELOST:
6362 ResourceList *resourceList = This->resources;
6363 while (NULL != resourceList) {
6364 if (((IWineD3DResourceImpl *)resourceList->resource)->resource.pool == WINED3DPOOL_DEFAULT /* TODO: IWineD3DResource_GetPool(resourceList->resource)*/)
6365 return WINED3DERR_DEVICENOTRESET;
6366 resourceList = resourceList->next;
6368 return WINED3DERR_DEVICELOST;
6370 case WINED3DERR_DRIVERINTERNALERROR:
6371 return WINED3DERR_DRIVERINTERNALERROR;
6374 /* Unknown state */
6375 return WINED3DERR_DRIVERINTERNALERROR;
6379 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6381 /** FIXME: Resource tracking needs to be done,
6382 * The closes we can do to this is set the priorities of all managed textures low
6383 * and then reset them.
6384 ***********************************************************/
6385 FIXME("(%p) : stub\n", This);
6386 return WINED3D_OK;
6389 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6390 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6392 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6393 if(surface->Flags & SFLAG_DIBSECTION) {
6394 /* Release the DC */
6395 SelectObject(surface->hDC, surface->dib.holdbitmap);
6396 DeleteDC(surface->hDC);
6397 /* Release the DIB section */
6398 DeleteObject(surface->dib.DIBsection);
6399 surface->dib.bitmap_data = NULL;
6400 surface->resource.allocatedMemory = NULL;
6401 surface->Flags &= ~SFLAG_DIBSECTION;
6403 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6404 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6405 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
6406 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6407 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6408 } else {
6409 surface->pow2Width = surface->pow2Height = 1;
6410 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6411 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6413 if(surface->glDescription.textureName) {
6414 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6415 ENTER_GL();
6416 glDeleteTextures(1, &surface->glDescription.textureName);
6417 LEAVE_GL();
6418 surface->glDescription.textureName = 0;
6419 surface->Flags &= ~SFLAG_CLIENT;
6421 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6422 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6423 surface->Flags |= SFLAG_NONPOW2;
6424 } else {
6425 surface->Flags &= ~SFLAG_NONPOW2;
6427 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6428 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6431 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6433 IWineD3DSwapChainImpl *swapchain;
6434 HRESULT hr;
6435 BOOL DisplayModeChanged = FALSE;
6436 WINED3DDISPLAYMODE mode;
6437 TRACE("(%p)\n", This);
6439 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6440 if(FAILED(hr)) {
6441 ERR("Failed to get the first implicit swapchain\n");
6442 return hr;
6445 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6446 * on an existing gl context, so there's no real need for recreation.
6448 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6450 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6452 TRACE("New params:\n");
6453 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6454 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6455 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6456 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6457 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6458 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6459 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6460 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6461 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6462 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6463 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6464 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6465 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6467 /* No special treatment of these parameters. Just store them */
6468 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6469 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6470 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6471 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6473 /* What to do about these? */
6474 if(pPresentationParameters->BackBufferCount != 0 &&
6475 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6476 ERR("Cannot change the back buffer count yet\n");
6478 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6479 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6480 ERR("Cannot change the back buffer format yet\n");
6482 if(pPresentationParameters->hDeviceWindow != NULL &&
6483 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6484 ERR("Cannot change the device window yet\n");
6486 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6487 ERR("What do do about a changed auto depth stencil parameter?\n");
6490 if(pPresentationParameters->Windowed) {
6491 mode.Width = swapchain->orig_width;
6492 mode.Height = swapchain->orig_height;
6493 mode.RefreshRate = 0;
6494 mode.Format = swapchain->presentParms.BackBufferFormat;
6495 } else {
6496 mode.Width = pPresentationParameters->BackBufferWidth;
6497 mode.Height = pPresentationParameters->BackBufferHeight;
6498 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6499 mode.Format = swapchain->presentParms.BackBufferFormat;
6501 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
6502 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
6503 pPresentationParameters->BackBufferWidth,
6504 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
6507 /* Should Width == 800 && Height == 0 set 800x600? */
6508 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6509 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6510 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6512 WINED3DVIEWPORT vp;
6513 int i;
6515 vp.X = 0;
6516 vp.Y = 0;
6517 vp.Width = pPresentationParameters->BackBufferWidth;
6518 vp.Height = pPresentationParameters->BackBufferHeight;
6519 vp.MinZ = 0;
6520 vp.MaxZ = 1;
6522 if(!pPresentationParameters->Windowed) {
6523 DisplayModeChanged = TRUE;
6525 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6526 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6528 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6529 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6530 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6533 /* Now set the new viewport */
6534 IWineD3DDevice_SetViewport(iface, &vp);
6537 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6538 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6539 DisplayModeChanged) {
6541 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
6542 if(!pPresentationParameters->Windowed) {
6543 IWineD3DDevice_SetFullscreen(iface, TRUE);
6546 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
6548 /* Switching out of fullscreen mode? First set the original res, then change the window */
6549 if(pPresentationParameters->Windowed) {
6550 IWineD3DDevice_SetFullscreen(iface, FALSE);
6552 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
6555 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
6556 return WINED3D_OK;
6559 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
6560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6561 /** FIXME: always true at the moment **/
6562 if(!bEnableDialogs) {
6563 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
6565 return WINED3D_OK;
6569 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
6570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6571 TRACE("(%p) : pParameters %p\n", This, pParameters);
6573 *pParameters = This->createParms;
6574 return WINED3D_OK;
6577 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
6578 IWineD3DSwapChain *swapchain;
6579 HRESULT hrc = WINED3D_OK;
6581 TRACE("Relaying to swapchain\n");
6583 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6584 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
6585 IWineD3DSwapChain_Release(swapchain);
6587 return;
6590 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
6591 IWineD3DSwapChain *swapchain;
6592 HRESULT hrc = WINED3D_OK;
6594 TRACE("Relaying to swapchain\n");
6596 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
6597 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
6598 IWineD3DSwapChain_Release(swapchain);
6600 return;
6604 /** ********************************************************
6605 * Notification functions
6606 ** ********************************************************/
6607 /** This function must be called in the release of a resource when ref == 0,
6608 * the contents of resource must still be correct,
6609 * any handels to other resource held by the caller must be closed
6610 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
6611 *****************************************************/
6612 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6614 ResourceList* resourceList;
6616 TRACE("(%p) : resource %p\n", This, resource);
6617 /* add a new texture to the frot of the linked list */
6618 resourceList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ResourceList));
6619 resourceList->resource = resource;
6621 /* Get the old head */
6622 resourceList->next = This->resources;
6624 This->resources = resourceList;
6625 TRACE("Added resource %p with element %p pointing to %p\n", resource, resourceList, resourceList->next);
6627 return;
6630 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
6631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6632 ResourceList* resourceList = NULL;
6633 ResourceList* previousResourceList = NULL;
6635 TRACE("(%p) : resource %p\n", This, resource);
6637 resourceList = This->resources;
6639 while (resourceList != NULL) {
6640 if(resourceList->resource == resource) break;
6641 previousResourceList = resourceList;
6642 resourceList = resourceList->next;
6645 if (resourceList == NULL) {
6646 FIXME("Attempted to remove resource %p that hasn't been stored\n", resource);
6647 return;
6648 } else {
6649 TRACE("Found resource %p with element %p pointing to %p (previous %p)\n", resourceList->resource, resourceList, resourceList->next, previousResourceList);
6651 /* make sure we don't leave a hole in the list */
6652 if (previousResourceList != NULL) {
6653 previousResourceList->next = resourceList->next;
6654 } else {
6655 This->resources = resourceList->next;
6658 return;
6662 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
6663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6664 int counter;
6666 TRACE("(%p) : resource %p\n", This, resource);
6667 switch(IWineD3DResource_GetType(resource)){
6668 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
6669 case WINED3DRTYPE_SURFACE: {
6670 unsigned int i;
6672 /* Cleanup any FBO attachments if d3d is enabled */
6673 if(This->d3d_initialized) {
6674 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6675 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
6676 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6677 set_render_target_fbo(iface, i, NULL);
6678 This->fbo_color_attachments[i] = NULL;
6681 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
6682 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6683 set_depth_stencil_fbo(iface, NULL);
6684 This->fbo_depth_attachment = NULL;
6688 break;
6690 case WINED3DRTYPE_TEXTURE:
6691 case WINED3DRTYPE_CUBETEXTURE:
6692 case WINED3DRTYPE_VOLUMETEXTURE:
6693 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
6694 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6695 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6696 This->stateBlock->textures[counter] = NULL;
6698 if (This->updateStateBlock != This->stateBlock ){
6699 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
6700 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
6701 This->updateStateBlock->textures[counter] = NULL;
6705 break;
6706 case WINED3DRTYPE_VOLUME:
6707 /* TODO: nothing really? */
6708 break;
6709 case WINED3DRTYPE_VERTEXBUFFER:
6710 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
6712 int streamNumber;
6713 TRACE("Cleaning up stream pointers\n");
6715 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
6716 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
6717 FINDOUT: should changes.streamSource[StreamNumber] be set ?
6719 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6720 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
6721 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6722 This->updateStateBlock->streamSource[streamNumber] = 0;
6723 /* Set changed flag? */
6726 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) */
6727 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
6728 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
6729 This->stateBlock->streamSource[streamNumber] = 0;
6732 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
6733 else { /* This shouldn't happen */
6734 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
6736 #endif
6740 break;
6741 case WINED3DRTYPE_INDEXBUFFER:
6742 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
6743 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
6744 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6745 This->updateStateBlock->pIndexData = NULL;
6748 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
6749 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
6750 This->stateBlock->pIndexData = NULL;
6754 break;
6755 default:
6756 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
6757 break;
6761 /* Remove the resoruce from the resourceStore */
6762 IWineD3DDeviceImpl_RemoveResource(iface, resource);
6764 TRACE("Resource released\n");
6768 /**********************************************************
6769 * IWineD3DDevice VTbl follows
6770 **********************************************************/
6772 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
6774 /*** IUnknown methods ***/
6775 IWineD3DDeviceImpl_QueryInterface,
6776 IWineD3DDeviceImpl_AddRef,
6777 IWineD3DDeviceImpl_Release,
6778 /*** IWineD3DDevice methods ***/
6779 IWineD3DDeviceImpl_GetParent,
6780 /*** Creation methods**/
6781 IWineD3DDeviceImpl_CreateVertexBuffer,
6782 IWineD3DDeviceImpl_CreateIndexBuffer,
6783 IWineD3DDeviceImpl_CreateStateBlock,
6784 IWineD3DDeviceImpl_CreateSurface,
6785 IWineD3DDeviceImpl_CreateTexture,
6786 IWineD3DDeviceImpl_CreateVolumeTexture,
6787 IWineD3DDeviceImpl_CreateVolume,
6788 IWineD3DDeviceImpl_CreateCubeTexture,
6789 IWineD3DDeviceImpl_CreateQuery,
6790 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
6791 IWineD3DDeviceImpl_CreateVertexDeclaration,
6792 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
6793 IWineD3DDeviceImpl_CreateVertexShader,
6794 IWineD3DDeviceImpl_CreatePixelShader,
6795 IWineD3DDeviceImpl_CreatePalette,
6796 /*** Odd functions **/
6797 IWineD3DDeviceImpl_Init3D,
6798 IWineD3DDeviceImpl_Uninit3D,
6799 IWineD3DDeviceImpl_SetFullscreen,
6800 IWineD3DDeviceImpl_SetMultithreaded,
6801 IWineD3DDeviceImpl_EvictManagedResources,
6802 IWineD3DDeviceImpl_GetAvailableTextureMem,
6803 IWineD3DDeviceImpl_GetBackBuffer,
6804 IWineD3DDeviceImpl_GetCreationParameters,
6805 IWineD3DDeviceImpl_GetDeviceCaps,
6806 IWineD3DDeviceImpl_GetDirect3D,
6807 IWineD3DDeviceImpl_GetDisplayMode,
6808 IWineD3DDeviceImpl_SetDisplayMode,
6809 IWineD3DDeviceImpl_GetHWND,
6810 IWineD3DDeviceImpl_SetHWND,
6811 IWineD3DDeviceImpl_GetNumberOfSwapChains,
6812 IWineD3DDeviceImpl_GetRasterStatus,
6813 IWineD3DDeviceImpl_GetSwapChain,
6814 IWineD3DDeviceImpl_Reset,
6815 IWineD3DDeviceImpl_SetDialogBoxMode,
6816 IWineD3DDeviceImpl_SetCursorProperties,
6817 IWineD3DDeviceImpl_SetCursorPosition,
6818 IWineD3DDeviceImpl_ShowCursor,
6819 IWineD3DDeviceImpl_TestCooperativeLevel,
6820 /*** Getters and setters **/
6821 IWineD3DDeviceImpl_SetClipPlane,
6822 IWineD3DDeviceImpl_GetClipPlane,
6823 IWineD3DDeviceImpl_SetClipStatus,
6824 IWineD3DDeviceImpl_GetClipStatus,
6825 IWineD3DDeviceImpl_SetCurrentTexturePalette,
6826 IWineD3DDeviceImpl_GetCurrentTexturePalette,
6827 IWineD3DDeviceImpl_SetDepthStencilSurface,
6828 IWineD3DDeviceImpl_GetDepthStencilSurface,
6829 IWineD3DDeviceImpl_SetFVF,
6830 IWineD3DDeviceImpl_GetFVF,
6831 IWineD3DDeviceImpl_SetGammaRamp,
6832 IWineD3DDeviceImpl_GetGammaRamp,
6833 IWineD3DDeviceImpl_SetIndices,
6834 IWineD3DDeviceImpl_GetIndices,
6835 IWineD3DDeviceImpl_SetBaseVertexIndex,
6836 IWineD3DDeviceImpl_GetBaseVertexIndex,
6837 IWineD3DDeviceImpl_SetLight,
6838 IWineD3DDeviceImpl_GetLight,
6839 IWineD3DDeviceImpl_SetLightEnable,
6840 IWineD3DDeviceImpl_GetLightEnable,
6841 IWineD3DDeviceImpl_SetMaterial,
6842 IWineD3DDeviceImpl_GetMaterial,
6843 IWineD3DDeviceImpl_SetNPatchMode,
6844 IWineD3DDeviceImpl_GetNPatchMode,
6845 IWineD3DDeviceImpl_SetPaletteEntries,
6846 IWineD3DDeviceImpl_GetPaletteEntries,
6847 IWineD3DDeviceImpl_SetPixelShader,
6848 IWineD3DDeviceImpl_GetPixelShader,
6849 IWineD3DDeviceImpl_SetPixelShaderConstantB,
6850 IWineD3DDeviceImpl_GetPixelShaderConstantB,
6851 IWineD3DDeviceImpl_SetPixelShaderConstantI,
6852 IWineD3DDeviceImpl_GetPixelShaderConstantI,
6853 IWineD3DDeviceImpl_SetPixelShaderConstantF,
6854 IWineD3DDeviceImpl_GetPixelShaderConstantF,
6855 IWineD3DDeviceImpl_SetRenderState,
6856 IWineD3DDeviceImpl_GetRenderState,
6857 IWineD3DDeviceImpl_SetRenderTarget,
6858 IWineD3DDeviceImpl_GetRenderTarget,
6859 IWineD3DDeviceImpl_SetFrontBackBuffers,
6860 IWineD3DDeviceImpl_SetSamplerState,
6861 IWineD3DDeviceImpl_GetSamplerState,
6862 IWineD3DDeviceImpl_SetScissorRect,
6863 IWineD3DDeviceImpl_GetScissorRect,
6864 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
6865 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
6866 IWineD3DDeviceImpl_SetStreamSource,
6867 IWineD3DDeviceImpl_GetStreamSource,
6868 IWineD3DDeviceImpl_SetStreamSourceFreq,
6869 IWineD3DDeviceImpl_GetStreamSourceFreq,
6870 IWineD3DDeviceImpl_SetTexture,
6871 IWineD3DDeviceImpl_GetTexture,
6872 IWineD3DDeviceImpl_SetTextureStageState,
6873 IWineD3DDeviceImpl_GetTextureStageState,
6874 IWineD3DDeviceImpl_SetTransform,
6875 IWineD3DDeviceImpl_GetTransform,
6876 IWineD3DDeviceImpl_SetVertexDeclaration,
6877 IWineD3DDeviceImpl_GetVertexDeclaration,
6878 IWineD3DDeviceImpl_SetVertexShader,
6879 IWineD3DDeviceImpl_GetVertexShader,
6880 IWineD3DDeviceImpl_SetVertexShaderConstantB,
6881 IWineD3DDeviceImpl_GetVertexShaderConstantB,
6882 IWineD3DDeviceImpl_SetVertexShaderConstantI,
6883 IWineD3DDeviceImpl_GetVertexShaderConstantI,
6884 IWineD3DDeviceImpl_SetVertexShaderConstantF,
6885 IWineD3DDeviceImpl_GetVertexShaderConstantF,
6886 IWineD3DDeviceImpl_SetViewport,
6887 IWineD3DDeviceImpl_GetViewport,
6888 IWineD3DDeviceImpl_MultiplyTransform,
6889 IWineD3DDeviceImpl_ValidateDevice,
6890 IWineD3DDeviceImpl_ProcessVertices,
6891 /*** State block ***/
6892 IWineD3DDeviceImpl_BeginStateBlock,
6893 IWineD3DDeviceImpl_EndStateBlock,
6894 /*** Scene management ***/
6895 IWineD3DDeviceImpl_BeginScene,
6896 IWineD3DDeviceImpl_EndScene,
6897 IWineD3DDeviceImpl_Present,
6898 IWineD3DDeviceImpl_Clear,
6899 /*** Drawing ***/
6900 IWineD3DDeviceImpl_DrawPrimitive,
6901 IWineD3DDeviceImpl_DrawIndexedPrimitive,
6902 IWineD3DDeviceImpl_DrawPrimitiveUP,
6903 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
6904 IWineD3DDeviceImpl_DrawPrimitiveStrided,
6905 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
6906 IWineD3DDeviceImpl_DrawRectPatch,
6907 IWineD3DDeviceImpl_DrawTriPatch,
6908 IWineD3DDeviceImpl_DeletePatch,
6909 IWineD3DDeviceImpl_ColorFill,
6910 IWineD3DDeviceImpl_UpdateTexture,
6911 IWineD3DDeviceImpl_UpdateSurface,
6912 IWineD3DDeviceImpl_GetFrontBufferData,
6913 /*** object tracking ***/
6914 IWineD3DDeviceImpl_ResourceReleased
6918 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
6919 WINED3DRS_ALPHABLENDENABLE ,
6920 WINED3DRS_ALPHAFUNC ,
6921 WINED3DRS_ALPHAREF ,
6922 WINED3DRS_ALPHATESTENABLE ,
6923 WINED3DRS_BLENDOP ,
6924 WINED3DRS_COLORWRITEENABLE ,
6925 WINED3DRS_DESTBLEND ,
6926 WINED3DRS_DITHERENABLE ,
6927 WINED3DRS_FILLMODE ,
6928 WINED3DRS_FOGDENSITY ,
6929 WINED3DRS_FOGEND ,
6930 WINED3DRS_FOGSTART ,
6931 WINED3DRS_LASTPIXEL ,
6932 WINED3DRS_SHADEMODE ,
6933 WINED3DRS_SRCBLEND ,
6934 WINED3DRS_STENCILENABLE ,
6935 WINED3DRS_STENCILFAIL ,
6936 WINED3DRS_STENCILFUNC ,
6937 WINED3DRS_STENCILMASK ,
6938 WINED3DRS_STENCILPASS ,
6939 WINED3DRS_STENCILREF ,
6940 WINED3DRS_STENCILWRITEMASK ,
6941 WINED3DRS_STENCILZFAIL ,
6942 WINED3DRS_TEXTUREFACTOR ,
6943 WINED3DRS_WRAP0 ,
6944 WINED3DRS_WRAP1 ,
6945 WINED3DRS_WRAP2 ,
6946 WINED3DRS_WRAP3 ,
6947 WINED3DRS_WRAP4 ,
6948 WINED3DRS_WRAP5 ,
6949 WINED3DRS_WRAP6 ,
6950 WINED3DRS_WRAP7 ,
6951 WINED3DRS_ZENABLE ,
6952 WINED3DRS_ZFUNC ,
6953 WINED3DRS_ZWRITEENABLE
6956 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
6957 WINED3DTSS_ADDRESSW ,
6958 WINED3DTSS_ALPHAARG0 ,
6959 WINED3DTSS_ALPHAARG1 ,
6960 WINED3DTSS_ALPHAARG2 ,
6961 WINED3DTSS_ALPHAOP ,
6962 WINED3DTSS_BUMPENVLOFFSET ,
6963 WINED3DTSS_BUMPENVLSCALE ,
6964 WINED3DTSS_BUMPENVMAT00 ,
6965 WINED3DTSS_BUMPENVMAT01 ,
6966 WINED3DTSS_BUMPENVMAT10 ,
6967 WINED3DTSS_BUMPENVMAT11 ,
6968 WINED3DTSS_COLORARG0 ,
6969 WINED3DTSS_COLORARG1 ,
6970 WINED3DTSS_COLORARG2 ,
6971 WINED3DTSS_COLOROP ,
6972 WINED3DTSS_RESULTARG ,
6973 WINED3DTSS_TEXCOORDINDEX ,
6974 WINED3DTSS_TEXTURETRANSFORMFLAGS
6977 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
6978 WINED3DSAMP_ADDRESSU ,
6979 WINED3DSAMP_ADDRESSV ,
6980 WINED3DSAMP_ADDRESSW ,
6981 WINED3DSAMP_BORDERCOLOR ,
6982 WINED3DSAMP_MAGFILTER ,
6983 WINED3DSAMP_MINFILTER ,
6984 WINED3DSAMP_MIPFILTER ,
6985 WINED3DSAMP_MIPMAPLODBIAS ,
6986 WINED3DSAMP_MAXMIPLEVEL ,
6987 WINED3DSAMP_MAXANISOTROPY ,
6988 WINED3DSAMP_SRGBTEXTURE ,
6989 WINED3DSAMP_ELEMENTINDEX
6992 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
6993 WINED3DRS_AMBIENT ,
6994 WINED3DRS_AMBIENTMATERIALSOURCE ,
6995 WINED3DRS_CLIPPING ,
6996 WINED3DRS_CLIPPLANEENABLE ,
6997 WINED3DRS_COLORVERTEX ,
6998 WINED3DRS_DIFFUSEMATERIALSOURCE ,
6999 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7000 WINED3DRS_FOGDENSITY ,
7001 WINED3DRS_FOGEND ,
7002 WINED3DRS_FOGSTART ,
7003 WINED3DRS_FOGTABLEMODE ,
7004 WINED3DRS_FOGVERTEXMODE ,
7005 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7006 WINED3DRS_LIGHTING ,
7007 WINED3DRS_LOCALVIEWER ,
7008 WINED3DRS_MULTISAMPLEANTIALIAS ,
7009 WINED3DRS_MULTISAMPLEMASK ,
7010 WINED3DRS_NORMALIZENORMALS ,
7011 WINED3DRS_PATCHEDGESTYLE ,
7012 WINED3DRS_POINTSCALE_A ,
7013 WINED3DRS_POINTSCALE_B ,
7014 WINED3DRS_POINTSCALE_C ,
7015 WINED3DRS_POINTSCALEENABLE ,
7016 WINED3DRS_POINTSIZE ,
7017 WINED3DRS_POINTSIZE_MAX ,
7018 WINED3DRS_POINTSIZE_MIN ,
7019 WINED3DRS_POINTSPRITEENABLE ,
7020 WINED3DRS_RANGEFOGENABLE ,
7021 WINED3DRS_SPECULARMATERIALSOURCE ,
7022 WINED3DRS_TWEENFACTOR ,
7023 WINED3DRS_VERTEXBLEND ,
7024 WINED3DRS_CULLMODE ,
7025 WINED3DRS_FOGCOLOR
7028 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7029 WINED3DTSS_TEXCOORDINDEX ,
7030 WINED3DTSS_TEXTURETRANSFORMFLAGS
7033 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7034 WINED3DSAMP_DMAPOFFSET
7037 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7038 DWORD rep = StateTable[state].representative;
7039 DWORD idx;
7040 BYTE shift;
7041 UINT i;
7042 WineD3DContext *context;
7044 if(!rep) return;
7045 for(i = 0; i < This->numContexts; i++) {
7046 context = This->contexts[i];
7047 if(isStateDirty(context, rep)) continue;
7049 context->dirtyArray[context->numDirtyEntries++] = rep;
7050 idx = rep >> 5;
7051 shift = rep & 0x1f;
7052 context->isStateDirty[idx] |= (1 << shift);