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
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 */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
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; \
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->baseShader.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); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 This->shader_backend->shader_free_private(iface);
178 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
180 /* TODO: Clean up all the surfaces and textures! */
181 /* NOTE: You must release the parent if the object was created via a callback
182 ** ***************************/
184 if (!list_empty(&This->resources)) {
185 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
186 dumpResources(&This->resources);
189 if(This->contexts) ERR("Context array not freed!\n");
190 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
191 This->haveHardwareCursor = FALSE;
193 IWineD3D_Release(This->wineD3D);
194 This->wineD3D = NULL;
195 HeapFree(GetProcessHeap(), 0, This);
196 TRACE("Freed device %p\n", This);
202 /**********************************************************
203 * IWineD3DDevice implementation follows
204 **********************************************************/
205 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
207 *pParent = This->parent;
208 IUnknown_AddRef(This->parent);
212 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
213 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
216 IWineD3DVertexBufferImpl *object;
217 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
218 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
222 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
223 *ppVertexBuffer = NULL;
224 return WINED3DERR_INVALIDCALL;
225 } else if(Pool == WINED3DPOOL_SCRATCH) {
226 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
227 * anyway, SCRATCH vertex buffers aren't useable anywhere
229 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
230 *ppVertexBuffer = NULL;
231 return WINED3DERR_INVALIDCALL;
234 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
236 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
237 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
241 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
242 * drawStridedFast (half-life 2).
244 * Basically converting the vertices in the buffer is quite expensive, and observations
245 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
246 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
248 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
249 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
250 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
251 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
253 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
254 * more. In this call we can convert dx7 buffers too.
256 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
257 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
258 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
259 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
260 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
261 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
262 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
263 } else if(dxVersion <= 7 && conv) {
264 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
266 object->Flags |= VBFLAG_CREATEVBO;
271 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
272 GLenum error, glUsage;
273 TRACE("Creating VBO for Index Buffer %p\n", object);
275 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
276 * restored on the next draw
278 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
280 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
281 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
286 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
287 error = glGetError();
288 if(error != GL_NO_ERROR || object->vbo == 0) {
289 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
294 error = glGetError();
295 if(error != GL_NO_ERROR) {
296 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
300 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
301 * copy no readback will be needed
303 glUsage = GL_STATIC_DRAW_ARB;
304 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
305 error = glGetError();
306 if(error != GL_NO_ERROR) {
307 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
311 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
315 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
316 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
321 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
322 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
323 HANDLE *sharedHandle, IUnknown *parent) {
324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
325 IWineD3DIndexBufferImpl *object;
326 TRACE("(%p) Creating index buffer\n", This);
328 /* Allocate the storage for the device */
329 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
331 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
332 CreateIndexBufferVBO(This, object);
335 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
336 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
337 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
342 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
345 IWineD3DStateBlockImpl *object;
349 D3DCREATEOBJECTINSTANCE(object, StateBlock)
350 object->blockType = Type;
352 for(i = 0; i < LIGHTMAP_SIZE; i++) {
353 list_init(&object->lightMap[i]);
356 /* Special case - Used during initialization to produce a placeholder stateblock
357 so other functions called can update a state block */
358 if (Type == WINED3DSBT_INIT) {
359 /* Don't bother increasing the reference count otherwise a device will never
360 be freed due to circular dependencies */
364 temp_result = allocate_shader_constants(object);
365 if (WINED3D_OK != temp_result)
368 /* Otherwise, might as well set the whole state block to the appropriate values */
369 if (This->stateBlock != NULL)
370 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
372 memset(object->streamFreq, 1, sizeof(object->streamFreq));
374 /* Reset the ref and type after kludging it */
375 object->wineD3DDevice = This;
377 object->blockType = Type;
379 TRACE("Updating changed flags appropriate for type %d\n", Type);
381 if (Type == WINED3DSBT_ALL) {
383 TRACE("ALL => Pretend everything has changed\n");
384 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
386 /* Lights are not part of the changed / set structure */
387 for(j = 0; j < LIGHTMAP_SIZE; j++) {
389 LIST_FOR_EACH(e, &object->lightMap[j]) {
390 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
391 light->changed = TRUE;
392 light->enabledChanged = TRUE;
395 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
396 object->contained_render_states[j - 1] = j;
398 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
399 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
400 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
401 object->contained_transform_states[j - 1] = j;
403 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
404 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
405 object->contained_vs_consts_f[j] = j;
407 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
408 for(j = 0; j < MAX_CONST_I; j++) {
409 object->contained_vs_consts_i[j] = j;
411 object->num_contained_vs_consts_i = MAX_CONST_I;
412 for(j = 0; j < MAX_CONST_B; j++) {
413 object->contained_vs_consts_b[j] = j;
415 object->num_contained_vs_consts_b = MAX_CONST_B;
416 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
417 object->contained_ps_consts_f[j] = j;
419 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
420 for(j = 0; j < MAX_CONST_I; j++) {
421 object->contained_ps_consts_i[j] = j;
423 object->num_contained_ps_consts_i = MAX_CONST_I;
424 for(j = 0; j < MAX_CONST_B; j++) {
425 object->contained_ps_consts_b[j] = j;
427 object->num_contained_ps_consts_b = MAX_CONST_B;
428 for(i = 0; i < MAX_TEXTURES; i++) {
429 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
430 object->contained_tss_states[object->num_contained_tss_states].stage = i;
431 object->contained_tss_states[object->num_contained_tss_states].state = j;
432 object->num_contained_tss_states++;
435 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
436 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
437 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
438 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
439 object->num_contained_sampler_states++;
443 for(i = 0; i < MAX_STREAMS; i++) {
444 if(object->streamSource[i]) {
445 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
448 if(object->pIndexData) {
449 IWineD3DIndexBuffer_AddRef(object->pIndexData);
451 if(object->vertexShader) {
452 IWineD3DVertexShader_AddRef(object->vertexShader);
454 if(object->pixelShader) {
455 IWineD3DPixelShader_AddRef(object->pixelShader);
458 } else if (Type == WINED3DSBT_PIXELSTATE) {
460 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
461 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
463 object->changed.pixelShader = TRUE;
465 /* Pixel Shader Constants */
466 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
467 object->contained_ps_consts_f[i] = i;
468 object->changed.pixelShaderConstantsF[i] = TRUE;
470 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
471 for (i = 0; i < MAX_CONST_B; ++i) {
472 object->contained_ps_consts_b[i] = i;
473 object->changed.pixelShaderConstantsB[i] = TRUE;
475 object->num_contained_ps_consts_b = MAX_CONST_B;
476 for (i = 0; i < MAX_CONST_I; ++i) {
477 object->contained_ps_consts_i[i] = i;
478 object->changed.pixelShaderConstantsI[i] = TRUE;
480 object->num_contained_ps_consts_i = MAX_CONST_I;
482 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
483 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
484 object->contained_render_states[i] = SavedPixelStates_R[i];
486 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
487 for (j = 0; j < MAX_TEXTURES; j++) {
488 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
489 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
490 object->contained_tss_states[object->num_contained_tss_states].stage = j;
491 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
492 object->num_contained_tss_states++;
495 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
496 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
497 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
498 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
499 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
500 object->num_contained_sampler_states++;
503 if(object->pixelShader) {
504 IWineD3DPixelShader_AddRef(object->pixelShader);
507 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
508 * on them. This makes releasing the buffer easier
510 for(i = 0; i < MAX_STREAMS; i++) {
511 object->streamSource[i] = NULL;
513 object->pIndexData = NULL;
514 object->vertexShader = NULL;
516 } else if (Type == WINED3DSBT_VERTEXSTATE) {
518 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
519 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
521 object->changed.vertexShader = TRUE;
523 /* Vertex Shader Constants */
524 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
525 object->changed.vertexShaderConstantsF[i] = TRUE;
526 object->contained_vs_consts_f[i] = i;
528 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
529 for (i = 0; i < MAX_CONST_B; ++i) {
530 object->changed.vertexShaderConstantsB[i] = TRUE;
531 object->contained_vs_consts_b[i] = i;
533 object->num_contained_vs_consts_b = MAX_CONST_B;
534 for (i = 0; i < MAX_CONST_I; ++i) {
535 object->changed.vertexShaderConstantsI[i] = TRUE;
536 object->contained_vs_consts_i[i] = i;
538 object->num_contained_vs_consts_i = MAX_CONST_I;
539 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
540 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
541 object->contained_render_states[i] = SavedVertexStates_R[i];
543 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
544 for (j = 0; j < MAX_TEXTURES; j++) {
545 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
546 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
547 object->contained_tss_states[object->num_contained_tss_states].stage = j;
548 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
549 object->num_contained_tss_states++;
552 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
553 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
554 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
555 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
556 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
557 object->num_contained_sampler_states++;
561 for(j = 0; j < LIGHTMAP_SIZE; j++) {
563 LIST_FOR_EACH(e, &object->lightMap[j]) {
564 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
565 light->changed = TRUE;
566 light->enabledChanged = TRUE;
570 for(i = 0; i < MAX_STREAMS; i++) {
571 if(object->streamSource[i]) {
572 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
575 if(object->vertexShader) {
576 IWineD3DVertexShader_AddRef(object->vertexShader);
578 object->pIndexData = NULL;
579 object->pixelShader = NULL;
581 FIXME("Unrecognized state block type %d\n", Type);
584 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
588 /* ************************************
590 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
593 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
595 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.
597 ******************************** */
599 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) {
600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
601 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
602 unsigned int Size = 1;
603 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
604 TRACE("(%p) Create surface\n",This);
606 /** FIXME: Check ranges on the inputs are valid
609 * [in] Quality level. The valid range is between zero and one less than the level
610 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
611 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
612 * values of paired render targets, depth stencil surfaces, and the MultiSample type
614 *******************************/
619 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
621 * If this flag is set, the contents of the depth stencil buffer will be
622 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
623 * with a different depth surface.
625 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
626 ***************************/
628 if(MultisampleQuality > 0) {
629 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
630 MultisampleQuality=0;
633 /** FIXME: Check that the format is supported
635 *******************************/
637 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
638 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
640 *********************************/
641 if (WINED3DFMT_UNKNOWN == Format) {
643 } else if (Format == WINED3DFMT_DXT1) {
644 /* DXT1 is half byte per pixel */
645 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
647 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
648 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
649 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
651 /* The pitch is a multiple of 4 bytes */
652 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
656 /** Create and initialise the surface resource **/
657 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
658 /* "Standalone" surface */
659 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
661 object->currentDesc.Width = Width;
662 object->currentDesc.Height = Height;
663 object->currentDesc.MultiSampleType = MultiSample;
664 object->currentDesc.MultiSampleQuality = MultisampleQuality;
665 object->glDescription.level = Level;
669 object->Flags |= Discard ? SFLAG_DISCARD : 0;
670 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
671 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
674 if (WINED3DFMT_UNKNOWN != Format) {
675 object->bytesPerPixel = tableEntry->bpp;
677 object->bytesPerPixel = 0;
680 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
682 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
684 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
685 * this function is too deep to need to care about things like this.
686 * Levels need to be checked too, and possibly Type since they all affect what can be done.
687 * ****************************************/
689 case WINED3DPOOL_SCRATCH:
691 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
692 "which are mutually exclusive, setting lockable to TRUE\n");
695 case WINED3DPOOL_SYSTEMMEM:
696 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
697 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
698 case WINED3DPOOL_MANAGED:
699 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
700 "Usage of DYNAMIC which are mutually exclusive, not doing "
701 "anything just telling you.\n");
703 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
704 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
705 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
706 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
709 FIXME("(%p) Unknown pool %d\n", This, Pool);
713 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
714 FIXME("Trying to create a render target that isn't in the default pool\n");
717 /* mark the texture as dirty so that it gets loaded first time around*/
718 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
719 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
720 This, Width, Height, Format, debug_d3dformat(Format),
721 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
723 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
724 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
725 This->ddraw_primary = (IWineD3DSurface *) object;
727 /* Look at the implementation and set the correct Vtable */
730 /* Check if a 3D adapter is available when creating gl surfaces */
732 ERR("OpenGL surfaces are not available without opengl\n");
733 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
734 HeapFree(GetProcessHeap(), 0, object);
735 return WINED3DERR_NOTAVAILABLE;
740 object->lpVtbl = &IWineGDISurface_Vtbl;
744 /* To be sure to catch this */
745 ERR("Unknown requested surface implementation %d!\n", Impl);
746 IWineD3DSurface_Release((IWineD3DSurface *) object);
747 return WINED3DERR_INVALIDCALL;
750 list_init(&object->renderbuffers);
752 /* Call the private setup routine */
753 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
757 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
758 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
759 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
760 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
762 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
763 IWineD3DTextureImpl *object;
768 unsigned int pow2Width;
769 unsigned int pow2Height;
770 const GlPixelFormatDesc *glDesc;
771 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
774 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
775 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
776 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
778 /* TODO: It should only be possible to create textures for formats
779 that are reported as supported */
780 if (WINED3DFMT_UNKNOWN >= Format) {
781 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
782 return WINED3DERR_INVALIDCALL;
785 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
786 D3DINITIALIZEBASETEXTURE(object->baseTexture);
787 object->width = Width;
788 object->height = Height;
790 /** Non-power2 support **/
791 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
795 /* Find the nearest pow2 match */
796 pow2Width = pow2Height = 1;
797 while (pow2Width < Width) pow2Width <<= 1;
798 while (pow2Height < Height) pow2Height <<= 1;
800 if(pow2Width != Width || pow2Height != Height) {
802 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
803 HeapFree(GetProcessHeap(), 0, object);
805 return WINED3DERR_INVALIDCALL;
812 /** FIXME: add support for real non-power-two if it's provided by the video card **/
813 /* Precalculated scaling for 'faked' non power of two texture coords.
814 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
815 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
816 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
818 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
819 (Width != pow2Width || Height != pow2Height) &&
820 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
822 object->baseTexture.pow2Matrix[0] = (float)Width;
823 object->baseTexture.pow2Matrix[5] = (float)Height;
824 object->baseTexture.pow2Matrix[10] = 1.0;
825 object->baseTexture.pow2Matrix[15] = 1.0;
826 object->target = GL_TEXTURE_RECTANGLE_ARB;
828 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
829 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
830 object->baseTexture.pow2Matrix[10] = 1.0;
831 object->baseTexture.pow2Matrix[15] = 1.0;
832 object->target = GL_TEXTURE_2D;
834 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
836 /* Calculate levels for mip mapping */
837 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
838 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
839 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
840 return WINED3DERR_INVALIDCALL;
843 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
844 return WINED3DERR_INVALIDCALL;
846 object->baseTexture.levels = 1;
847 } else if (Levels == 0) {
848 TRACE("calculating levels %d\n", object->baseTexture.levels);
849 object->baseTexture.levels++;
852 while (tmpW > 1 || tmpH > 1) {
853 tmpW = max(1, tmpW >> 1);
854 tmpH = max(1, tmpH >> 1);
855 object->baseTexture.levels++;
857 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
860 /* Generate all the surfaces */
863 for (i = 0; i < object->baseTexture.levels; i++)
865 /* use the callback to create the texture surface */
866 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
867 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
868 FIXME("Failed to create surface %p\n", object);
870 object->surfaces[i] = NULL;
871 IWineD3DTexture_Release((IWineD3DTexture *)object);
877 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
878 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
879 /* calculate the next mipmap level */
880 tmpW = max(1, tmpW >> 1);
881 tmpH = max(1, tmpH >> 1);
883 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
885 TRACE("(%p) : Created texture %p\n", This, object);
889 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
890 UINT Width, UINT Height, UINT Depth,
891 UINT Levels, DWORD Usage,
892 WINED3DFORMAT Format, WINED3DPOOL Pool,
893 IWineD3DVolumeTexture **ppVolumeTexture,
894 HANDLE *pSharedHandle, IUnknown *parent,
895 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
898 IWineD3DVolumeTextureImpl *object;
903 const GlPixelFormatDesc *glDesc;
905 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
907 /* TODO: It should only be possible to create textures for formats
908 that are reported as supported */
909 if (WINED3DFMT_UNKNOWN >= Format) {
910 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
911 return WINED3DERR_INVALIDCALL;
913 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
914 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
915 return WINED3DERR_INVALIDCALL;
918 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
919 D3DINITIALIZEBASETEXTURE(object->baseTexture);
921 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
922 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
924 object->width = Width;
925 object->height = Height;
926 object->depth = Depth;
928 /* Is NP2 support for volumes needed? */
929 object->baseTexture.pow2Matrix[ 0] = 1.0;
930 object->baseTexture.pow2Matrix[ 5] = 1.0;
931 object->baseTexture.pow2Matrix[10] = 1.0;
932 object->baseTexture.pow2Matrix[15] = 1.0;
934 /* Calculate levels for mip mapping */
935 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
936 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
937 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
938 return WINED3DERR_INVALIDCALL;
941 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
942 return WINED3DERR_INVALIDCALL;
945 } else if (Levels == 0) {
946 object->baseTexture.levels++;
950 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
951 tmpW = max(1, tmpW >> 1);
952 tmpH = max(1, tmpH >> 1);
953 tmpD = max(1, tmpD >> 1);
954 object->baseTexture.levels++;
956 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
959 /* Generate all the surfaces */
964 for (i = 0; i < object->baseTexture.levels; i++)
967 /* Create the volume */
968 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
969 &object->volumes[i], pSharedHandle);
972 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
973 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
974 *ppVolumeTexture = NULL;
978 /* Set its container to this object */
979 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
981 /* calculate the next mipmap level */
982 tmpW = max(1, tmpW >> 1);
983 tmpH = max(1, tmpH >> 1);
984 tmpD = max(1, tmpD >> 1);
986 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
988 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
989 TRACE("(%p) : Created volume texture %p\n", This, object);
993 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
994 UINT Width, UINT Height, UINT Depth,
996 WINED3DFORMAT Format, WINED3DPOOL Pool,
997 IWineD3DVolume** ppVolume,
998 HANDLE* pSharedHandle, IUnknown *parent) {
1000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1001 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1002 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1004 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1005 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1006 return WINED3DERR_INVALIDCALL;
1009 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1011 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1012 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1014 object->currentDesc.Width = Width;
1015 object->currentDesc.Height = Height;
1016 object->currentDesc.Depth = Depth;
1017 object->bytesPerPixel = formatDesc->bpp;
1019 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1020 object->lockable = TRUE;
1021 object->locked = FALSE;
1022 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1023 object->dirty = TRUE;
1025 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1028 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1029 UINT Levels, DWORD Usage,
1030 WINED3DFORMAT Format, WINED3DPOOL Pool,
1031 IWineD3DCubeTexture **ppCubeTexture,
1032 HANDLE *pSharedHandle, IUnknown *parent,
1033 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1036 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1040 unsigned int pow2EdgeLength = EdgeLength;
1041 const GlPixelFormatDesc *glDesc;
1042 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1044 /* TODO: It should only be possible to create textures for formats
1045 that are reported as supported */
1046 if (WINED3DFMT_UNKNOWN >= Format) {
1047 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1048 return WINED3DERR_INVALIDCALL;
1051 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1052 WARN("(%p) : Tried to create not supported cube texture\n", This);
1053 return WINED3DERR_INVALIDCALL;
1056 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1057 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1059 TRACE("(%p) Create Cube Texture\n", This);
1061 /** Non-power2 support **/
1063 /* Find the nearest pow2 match */
1065 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1067 object->edgeLength = EdgeLength;
1068 /* TODO: support for native non-power 2 */
1069 /* Precalculated scaling for 'faked' non power of two texture coords */
1070 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1073 object->baseTexture.pow2Matrix[15] = 1.0;
1075 /* Calculate levels for mip mapping */
1076 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1077 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1078 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1079 HeapFree(GetProcessHeap(), 0, object);
1080 *ppCubeTexture = NULL;
1082 return WINED3DERR_INVALIDCALL;
1085 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1086 HeapFree(GetProcessHeap(), 0, object);
1087 *ppCubeTexture = NULL;
1089 return WINED3DERR_INVALIDCALL;
1092 } else if (Levels == 0) {
1093 object->baseTexture.levels++;
1096 tmpW = max(1, tmpW >> 1);
1097 object->baseTexture.levels++;
1099 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1102 /* Generate all the surfaces */
1104 for (i = 0; i < object->baseTexture.levels; i++) {
1106 /* Create the 6 faces */
1107 for (j = 0; j < 6; j++) {
1109 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1110 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1112 if(hr!= WINED3D_OK) {
1116 for (l = 0; l < j; l++) {
1117 IWineD3DSurface_Release(object->surfaces[l][i]);
1119 for (k = 0; k < i; k++) {
1120 for (l = 0; l < 6; l++) {
1121 IWineD3DSurface_Release(object->surfaces[l][k]);
1125 FIXME("(%p) Failed to create surface\n",object);
1126 HeapFree(GetProcessHeap(),0,object);
1127 *ppCubeTexture = NULL;
1130 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1131 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1133 tmpW = max(1, tmpW >> 1);
1135 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1137 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1138 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1142 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1144 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1145 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1147 /* Just a check to see if we support this type of query */
1149 case WINED3DQUERYTYPE_OCCLUSION:
1150 TRACE("(%p) occlusion query\n", This);
1151 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1154 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1157 case WINED3DQUERYTYPE_EVENT:
1158 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1159 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1160 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1162 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1167 case WINED3DQUERYTYPE_VCACHE:
1168 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1169 case WINED3DQUERYTYPE_VERTEXSTATS:
1170 case WINED3DQUERYTYPE_TIMESTAMP:
1171 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1172 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1173 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1174 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1175 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1176 case WINED3DQUERYTYPE_PIXELTIMINGS:
1177 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1178 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1180 FIXME("(%p) Unhandled query type %d\n", This, Type);
1182 if(NULL == ppQuery || hr != WINED3D_OK) {
1186 D3DCREATEOBJECTINSTANCE(object, Query)
1187 object->type = Type;
1188 object->state = QUERY_CREATED;
1189 /* allocated the 'extended' data based on the type of query requested */
1191 case WINED3DQUERYTYPE_OCCLUSION:
1192 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1193 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1195 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1196 TRACE("(%p) Allocating data for an occlusion query\n", This);
1197 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1200 case WINED3DQUERYTYPE_EVENT:
1201 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1202 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1204 if(GL_SUPPORT(APPLE_FENCE)) {
1205 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1206 checkGLcall("glGenFencesAPPLE");
1207 } else if(GL_SUPPORT(NV_FENCE)) {
1208 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1209 checkGLcall("glGenFencesNV");
1213 case WINED3DQUERYTYPE_VCACHE:
1214 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1215 case WINED3DQUERYTYPE_VERTEXSTATS:
1216 case WINED3DQUERYTYPE_TIMESTAMP:
1217 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1218 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1219 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1220 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1221 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1222 case WINED3DQUERYTYPE_PIXELTIMINGS:
1223 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1224 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1226 object->extendedData = 0;
1227 FIXME("(%p) Unhandled query type %d\n",This , Type);
1229 TRACE("(%p) : Created Query %p\n", This, object);
1233 /*****************************************************************************
1234 * IWineD3DDeviceImpl_SetupFullscreenWindow
1236 * Helper function that modifies a HWND's Style and ExStyle for proper
1240 * iface: Pointer to the IWineD3DDevice interface
1241 * window: Window to setup
1243 *****************************************************************************/
1244 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1245 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1247 LONG style, exStyle;
1248 /* Don't do anything if an original style is stored.
1249 * That shouldn't happen
1251 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1252 if (This->style || This->exStyle) {
1253 ERR("(%p): Want to change the window parameters of HWND %p, but "
1254 "another style is stored for restoration afterwards\n", This, window);
1257 /* Get the parameters and save them */
1258 style = GetWindowLongW(window, GWL_STYLE);
1259 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1260 This->style = style;
1261 This->exStyle = exStyle;
1263 /* Filter out window decorations */
1264 style &= ~WS_CAPTION;
1265 style &= ~WS_THICKFRAME;
1266 exStyle &= ~WS_EX_WINDOWEDGE;
1267 exStyle &= ~WS_EX_CLIENTEDGE;
1269 /* Make sure the window is managed, otherwise we won't get keyboard input */
1270 style |= WS_POPUP | WS_SYSMENU;
1272 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1273 This->style, This->exStyle, style, exStyle);
1275 SetWindowLongW(window, GWL_STYLE, style);
1276 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1278 /* Inform the window about the update. */
1279 SetWindowPos(window, HWND_TOP, 0, 0,
1280 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1281 ShowWindow(window, SW_NORMAL);
1284 /*****************************************************************************
1285 * IWineD3DDeviceImpl_RestoreWindow
1287 * Helper function that restores a windows' properties when taking it out
1288 * of fullscreen mode
1291 * iface: Pointer to the IWineD3DDevice interface
1292 * window: Window to setup
1294 *****************************************************************************/
1295 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1298 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1299 * switch, do nothing
1301 if (!This->style && !This->exStyle) return;
1303 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1304 This, window, This->style, This->exStyle);
1306 SetWindowLongW(window, GWL_STYLE, This->style);
1307 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1309 /* Delete the old values */
1313 /* Inform the window about the update */
1314 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1315 0, 0, 0, 0, /* Pos, Size, ignored */
1316 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1319 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1320 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1322 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1323 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1327 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1328 HRESULT hr = WINED3D_OK;
1329 IUnknown *bufferParent;
1330 BOOL displaymode_set = FALSE;
1331 WINED3DDISPLAYMODE Mode;
1332 const StaticPixelFormatDesc *formatDesc;
1334 TRACE("(%p) : Created Additional Swap Chain\n", This);
1336 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1337 * does a device hold a reference to a swap chain giving them a lifetime of the device
1338 * or does the swap chain notify the device of its destruction.
1339 *******************************/
1341 /* Check the params */
1342 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1343 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1344 return WINED3DERR_INVALIDCALL;
1345 } else if (pPresentationParameters->BackBufferCount > 1) {
1346 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");
1349 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1351 /*********************
1352 * Lookup the window Handle and the relating X window handle
1353 ********************/
1355 /* Setup hwnd we are using, plus which display this equates to */
1356 object->win_handle = pPresentationParameters->hDeviceWindow;
1357 if (!object->win_handle) {
1358 object->win_handle = This->createParms.hFocusWindow;
1360 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1362 hDc = GetDC(object->win_handle);
1363 TRACE("Using hDc %p\n", hDc);
1366 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1367 return WINED3DERR_NOTAVAILABLE;
1370 /* Get info on the current display setup */
1371 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1372 object->orig_width = Mode.Width;
1373 object->orig_height = Mode.Height;
1374 object->orig_fmt = Mode.Format;
1375 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1377 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1378 * then the corresponding dimension of the client area of the hDeviceWindow
1379 * (or the focus window, if hDeviceWindow is NULL) is taken.
1380 **********************/
1382 if (pPresentationParameters->Windowed &&
1383 ((pPresentationParameters->BackBufferWidth == 0) ||
1384 (pPresentationParameters->BackBufferHeight == 0) ||
1385 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1388 GetClientRect(object->win_handle, &Rect);
1390 if (pPresentationParameters->BackBufferWidth == 0) {
1391 pPresentationParameters->BackBufferWidth = Rect.right;
1392 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1394 if (pPresentationParameters->BackBufferHeight == 0) {
1395 pPresentationParameters->BackBufferHeight = Rect.bottom;
1396 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1398 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1399 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1400 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1404 /* Put the correct figures in the presentation parameters */
1405 TRACE("Copying across presentation parameters\n");
1406 object->presentParms = *pPresentationParameters;
1408 TRACE("calling rendertarget CB\n");
1409 hr = D3DCB_CreateRenderTarget(This->parent,
1411 object->presentParms.BackBufferWidth,
1412 object->presentParms.BackBufferHeight,
1413 object->presentParms.BackBufferFormat,
1414 object->presentParms.MultiSampleType,
1415 object->presentParms.MultiSampleQuality,
1416 TRUE /* Lockable */,
1417 &object->frontBuffer,
1418 NULL /* pShared (always null)*/);
1419 if (object->frontBuffer != NULL) {
1420 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1421 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1423 ERR("Failed to create the front buffer\n");
1427 /*********************
1428 * Windowed / Fullscreen
1429 *******************/
1432 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1433 * so we should really check to see if there is a fullscreen swapchain already
1434 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1435 **************************************/
1437 if (!pPresentationParameters->Windowed) {
1438 WINED3DDISPLAYMODE mode;
1441 /* Change the display settings */
1442 mode.Width = pPresentationParameters->BackBufferWidth;
1443 mode.Height = pPresentationParameters->BackBufferHeight;
1444 mode.Format = pPresentationParameters->BackBufferFormat;
1445 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1447 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1448 displaymode_set = TRUE;
1449 IWineD3DDevice_SetFullscreen(iface, TRUE);
1453 * Create an opengl context for the display visual
1454 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1455 * use different properties after that point in time. FIXME: How to handle when requested format
1456 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1457 * it chooses is identical to the one already being used!
1458 **********************************/
1459 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1461 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1462 if(!object->context)
1463 return E_OUTOFMEMORY;
1464 object->num_contexts = 1;
1466 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1467 if (!object->context[0]) {
1468 ERR("Failed to create a new context\n");
1469 hr = WINED3DERR_NOTAVAILABLE;
1472 TRACE("Context created (HWND=%p, glContext=%p)\n",
1473 object->win_handle, object->context[0]->glCtx);
1476 /*********************
1477 * Create the back, front and stencil buffers
1478 *******************/
1479 if(object->presentParms.BackBufferCount > 0) {
1482 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1483 if(!object->backBuffer) {
1484 ERR("Out of memory\n");
1489 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1490 TRACE("calling rendertarget CB\n");
1491 hr = D3DCB_CreateRenderTarget(This->parent,
1493 object->presentParms.BackBufferWidth,
1494 object->presentParms.BackBufferHeight,
1495 object->presentParms.BackBufferFormat,
1496 object->presentParms.MultiSampleType,
1497 object->presentParms.MultiSampleQuality,
1498 TRUE /* Lockable */,
1499 &object->backBuffer[i],
1500 NULL /* pShared (always null)*/);
1501 if(hr == WINED3D_OK && object->backBuffer[i]) {
1502 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1504 ERR("Cannot create new back buffer\n");
1508 glDrawBuffer(GL_BACK);
1509 checkGLcall("glDrawBuffer(GL_BACK)");
1513 object->backBuffer = NULL;
1515 /* Single buffering - draw to front buffer */
1517 glDrawBuffer(GL_FRONT);
1518 checkGLcall("glDrawBuffer(GL_FRONT)");
1522 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1523 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1524 TRACE("Creating depth stencil buffer\n");
1525 if (This->auto_depth_stencil_buffer == NULL ) {
1526 hr = D3DCB_CreateDepthStencil(This->parent,
1528 object->presentParms.BackBufferWidth,
1529 object->presentParms.BackBufferHeight,
1530 object->presentParms.AutoDepthStencilFormat,
1531 object->presentParms.MultiSampleType,
1532 object->presentParms.MultiSampleQuality,
1533 FALSE /* FIXME: Discard */,
1534 &This->auto_depth_stencil_buffer,
1535 NULL /* pShared (always null)*/ );
1536 if (This->auto_depth_stencil_buffer != NULL)
1537 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1540 /** TODO: A check on width, height and multisample types
1541 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1542 ****************************/
1543 object->wantsDepthStencilBuffer = TRUE;
1545 object->wantsDepthStencilBuffer = FALSE;
1548 TRACE("Created swapchain %p\n", object);
1549 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1553 if (displaymode_set) {
1557 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1560 /* Change the display settings */
1561 memset(&devmode, 0, sizeof(devmode));
1562 devmode.dmSize = sizeof(devmode);
1563 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1564 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1565 devmode.dmPelsWidth = object->orig_width;
1566 devmode.dmPelsHeight = object->orig_height;
1567 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1570 if (object->backBuffer) {
1572 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1573 if(object->backBuffer[i]) {
1574 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1575 IUnknown_Release(bufferParent); /* once for the get parent */
1576 if (IUnknown_Release(bufferParent) > 0) {
1577 FIXME("(%p) Something's still holding the back buffer\n",This);
1581 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1582 object->backBuffer = NULL;
1584 if(object->context[0])
1585 DestroyContext(This, object->context[0]);
1586 if(object->frontBuffer) {
1587 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1588 IUnknown_Release(bufferParent); /* once for the get parent */
1589 if (IUnknown_Release(bufferParent) > 0) {
1590 FIXME("(%p) Something's still holding the front buffer\n",This);
1593 HeapFree(GetProcessHeap(), 0, object);
1597 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1598 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1600 TRACE("(%p)\n", This);
1602 return This->NumberOfSwapChains;
1605 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1607 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1609 if(iSwapChain < This->NumberOfSwapChains) {
1610 *pSwapChain = This->swapchains[iSwapChain];
1611 IWineD3DSwapChain_AddRef(*pSwapChain);
1612 TRACE("(%p) returning %p\n", This, *pSwapChain);
1615 TRACE("Swapchain out of range\n");
1617 return WINED3DERR_INVALIDCALL;
1622 * Vertex Declaration
1624 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1625 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1627 IWineD3DVertexDeclarationImpl *object = NULL;
1628 HRESULT hr = WINED3D_OK;
1630 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1631 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1633 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1635 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1637 *ppVertexDeclaration = NULL;
1638 HeapFree(GetProcessHeap(), 0, object);
1644 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1645 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1647 unsigned int idx, idx2;
1648 unsigned int offset;
1649 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1650 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1651 BOOL has_blend_idx = has_blend &&
1652 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1653 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1654 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1655 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1656 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1657 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1658 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1660 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1661 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1663 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1664 WINED3DVERTEXELEMENT *elements = NULL;
1667 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1668 if (has_blend_idx) num_blends--;
1670 /* Compute declaration size */
1671 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1672 has_psize + has_diffuse + has_specular + num_textures + 1;
1674 /* convert the declaration */
1675 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1679 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1682 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1683 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1684 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1687 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1688 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1690 elements[idx].UsageIndex = 0;
1693 if (has_blend && (num_blends > 0)) {
1694 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1695 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1697 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1698 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1699 elements[idx].UsageIndex = 0;
1702 if (has_blend_idx) {
1703 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1704 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1705 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1706 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1707 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1709 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1710 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1711 elements[idx].UsageIndex = 0;
1715 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1716 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1717 elements[idx].UsageIndex = 0;
1721 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1722 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1723 elements[idx].UsageIndex = 0;
1727 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1728 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1729 elements[idx].UsageIndex = 0;
1733 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1734 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1735 elements[idx].UsageIndex = 1;
1738 for (idx2 = 0; idx2 < num_textures; idx2++) {
1739 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1740 switch (numcoords) {
1741 case WINED3DFVF_TEXTUREFORMAT1:
1742 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1744 case WINED3DFVF_TEXTUREFORMAT2:
1745 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1747 case WINED3DFVF_TEXTUREFORMAT3:
1748 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1750 case WINED3DFVF_TEXTUREFORMAT4:
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1754 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1755 elements[idx].UsageIndex = idx2;
1759 /* Now compute offsets, and initialize the rest of the fields */
1760 for (idx = 0, offset = 0; idx < size-1; idx++) {
1761 elements[idx].Stream = 0;
1762 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1763 elements[idx].Offset = offset;
1764 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1767 *ppVertexElements = elements;
1771 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1772 WINED3DVERTEXELEMENT* elements = NULL;
1773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1777 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1778 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1780 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1781 HeapFree(GetProcessHeap(), 0, elements);
1782 if (hr != S_OK) return hr;
1787 /* http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/programmable/vertexshaders/vscreate.asp */
1788 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1789 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1790 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1791 HRESULT hr = WINED3D_OK;
1792 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1793 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1795 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1797 if (vertex_declaration) {
1798 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1801 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1803 if (WINED3D_OK != hr) {
1804 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1805 IWineD3DVertexShader_Release(*ppVertexShader);
1806 return WINED3DERR_INVALIDCALL;
1808 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1813 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1815 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1816 HRESULT hr = WINED3D_OK;
1818 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1819 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1820 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1821 if (WINED3D_OK == hr) {
1822 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1823 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1825 WARN("(%p) : Failed to create pixel shader\n", This);
1831 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1832 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1833 IWineD3DPaletteImpl *object;
1835 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1837 /* Create the new object */
1838 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1840 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1841 return E_OUTOFMEMORY;
1844 object->lpVtbl = &IWineD3DPalette_Vtbl;
1846 object->Flags = Flags;
1847 object->parent = Parent;
1848 object->wineD3DDevice = This;
1849 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1851 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1854 HeapFree( GetProcessHeap(), 0, object);
1855 return E_OUTOFMEMORY;
1858 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1860 IWineD3DPalette_Release((IWineD3DPalette *) object);
1864 *Palette = (IWineD3DPalette *) object;
1869 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1873 HDC dcb = NULL, dcs = NULL;
1874 WINEDDCOLORKEY colorkey;
1876 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1879 GetObjectA(hbm, sizeof(BITMAP), &bm);
1880 dcb = CreateCompatibleDC(NULL);
1882 SelectObject(dcb, hbm);
1886 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1887 * couldn't be loaded
1889 memset(&bm, 0, sizeof(bm));
1894 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1895 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1896 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1898 ERR("Wine logo requested, but failed to create surface\n");
1903 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1904 if(FAILED(hr)) goto out;
1905 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1906 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1908 colorkey.dwColorSpaceLowValue = 0;
1909 colorkey.dwColorSpaceHighValue = 0;
1910 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1912 /* Fill the surface with a white color to show that wined3d is there */
1913 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1926 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1928 /* Under DirectX you can have texture stage operations even if no texture is
1929 bound, whereas opengl will only do texture operations when a valid texture is
1930 bound. We emulate this by creating dummy textures and binding them to each
1931 texture stage, but disable all stages by default. Hence if a stage is enabled
1932 then the default texture will kick in until replaced by a SetTexture call */
1935 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1936 /* The dummy texture does not have client storage backing */
1937 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1938 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1940 for (i = 0; i < GL_LIMITS(textures); i++) {
1941 GLubyte white = 255;
1943 /* Make appropriate texture active */
1944 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1945 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1946 checkGLcall("glActiveTextureARB");
1948 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1951 /* Generate an opengl texture name */
1952 glGenTextures(1, &This->dummyTextureName[i]);
1953 checkGLcall("glGenTextures");
1954 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1956 /* Generate a dummy 2d texture (not using 1d because they cause many
1957 * DRI drivers fall back to sw) */
1958 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1959 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1960 checkGLcall("glBindTexture");
1962 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1963 checkGLcall("glTexImage2D");
1965 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1966 /* Reenable because if supported it is enabled by default */
1967 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1968 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1974 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1976 IWineD3DSwapChainImpl *swapchain = NULL;
1980 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1981 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1983 /* TODO: Test if OpenGL is compiled in and loaded */
1985 TRACE("(%p) : Creating stateblock\n", This);
1986 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1987 hr = IWineD3DDevice_CreateStateBlock(iface,
1989 (IWineD3DStateBlock **)&This->stateBlock,
1991 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1992 WARN("Failed to create stateblock\n");
1995 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
1996 This->updateStateBlock = This->stateBlock;
1997 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
1999 hr = allocate_shader_constants(This->updateStateBlock);
2000 if (WINED3D_OK != hr) {
2004 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2005 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2006 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2008 /* Initialize the texture unit mapping to a 1:1 mapping */
2009 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2010 if (state < GL_LIMITS(fragment_samplers)) {
2011 This->texUnitMap[state] = state;
2012 This->rev_tex_unit_map[state] = state;
2014 This->texUnitMap[state] = -1;
2015 This->rev_tex_unit_map[state] = -1;
2019 /* Setup the implicit swapchain */
2020 TRACE("Creating implicit swapchain\n");
2021 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2022 if (FAILED(hr) || !swapchain) {
2023 WARN("Failed to create implicit swapchain\n");
2027 This->NumberOfSwapChains = 1;
2028 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2029 if(!This->swapchains) {
2030 ERR("Out of memory!\n");
2033 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2035 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2036 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2037 This->render_targets[0] = swapchain->backBuffer[0];
2038 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2041 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2042 This->render_targets[0] = swapchain->frontBuffer;
2043 This->lastActiveRenderTarget = swapchain->frontBuffer;
2045 IWineD3DSurface_AddRef(This->render_targets[0]);
2046 This->activeContext = swapchain->context[0];
2047 This->lastThread = GetCurrentThreadId();
2049 /* Depth Stencil support */
2050 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2051 if (NULL != This->stencilBufferTarget) {
2052 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2055 /* Set up some starting GL setup */
2058 /* Setup all the devices defaults */
2059 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2060 create_dummy_textures(This);
2062 IWineD3DImpl_CheckGraphicsMemory();
2065 { /* Set a default viewport */
2069 vp.Width = pPresentationParameters->BackBufferWidth;
2070 vp.Height = pPresentationParameters->BackBufferHeight;
2073 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2076 /* Initialize the current view state */
2077 This->view_ident = 1;
2078 This->contexts[0]->last_was_rhw = 0;
2079 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2080 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2082 switch(wined3d_settings.offscreen_rendering_mode) {
2085 This->offscreenBuffer = GL_BACK;
2088 case ORM_BACKBUFFER:
2090 if(GL_LIMITS(aux_buffers) > 0) {
2091 TRACE("Using auxilliary buffer for offscreen rendering\n");
2092 This->offscreenBuffer = GL_AUX0;
2094 TRACE("Using back buffer for offscreen rendering\n");
2095 This->offscreenBuffer = GL_BACK;
2100 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2103 /* Clear the screen */
2104 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2105 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2108 This->d3d_initialized = TRUE;
2110 if(wined3d_settings.logo) {
2111 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2116 HeapFree(GetProcessHeap(), 0, This->render_targets);
2117 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2118 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2119 HeapFree(GetProcessHeap(), 0, This->swapchains);
2120 This->NumberOfSwapChains = 0;
2122 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2124 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2125 if(This->stateBlock) {
2126 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2127 This->stateBlock = NULL;
2132 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2133 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2136 TRACE("(%p)\n", This);
2138 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2140 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2141 * it was created. Thus make sure a context is active for the glDelete* calls
2143 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2145 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2147 TRACE("Deleting high order patches\n");
2148 for(i = 0; i < PATCHMAP_SIZE; i++) {
2149 struct list *e1, *e2;
2150 struct WineD3DRectPatch *patch;
2151 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2152 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2153 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2157 /* Delete the palette conversion shader if it is around */
2158 if(This->paletteConversionShader) {
2159 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2160 This->paletteConversionShader = 0;
2163 /* Delete the pbuffer context if there is any */
2164 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2166 /* Delete the mouse cursor texture */
2167 if(This->cursorTexture) {
2169 glDeleteTextures(1, &This->cursorTexture);
2171 This->cursorTexture = 0;
2174 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2175 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2177 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2178 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2181 /* Release the update stateblock */
2182 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2183 if(This->updateStateBlock != This->stateBlock)
2184 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2186 This->updateStateBlock = NULL;
2188 { /* because were not doing proper internal refcounts releasing the primary state block
2189 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2190 to set this->stateBlock = NULL; first */
2191 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2192 This->stateBlock = NULL;
2194 /* Release the stateblock */
2195 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2196 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2200 /* Release the buffers (with sanity checks)*/
2201 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2202 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2203 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2204 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2206 This->stencilBufferTarget = NULL;
2208 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2209 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2210 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2212 TRACE("Setting rendertarget to NULL\n");
2213 This->render_targets[0] = NULL;
2215 if (This->auto_depth_stencil_buffer) {
2216 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2217 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2219 This->auto_depth_stencil_buffer = NULL;
2222 for(i=0; i < This->NumberOfSwapChains; i++) {
2223 TRACE("Releasing the implicit swapchain %d\n", i);
2224 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2225 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2229 HeapFree(GetProcessHeap(), 0, This->swapchains);
2230 This->swapchains = NULL;
2231 This->NumberOfSwapChains = 0;
2233 HeapFree(GetProcessHeap(), 0, This->render_targets);
2234 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2235 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2236 This->render_targets = NULL;
2237 This->fbo_color_attachments = NULL;
2238 This->draw_buffers = NULL;
2241 This->d3d_initialized = FALSE;
2245 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2247 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2249 /* Setup the window for fullscreen mode */
2250 if(fullscreen && !This->ddraw_fullscreen) {
2251 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2252 } else if(!fullscreen && This->ddraw_fullscreen) {
2253 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2256 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2257 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2258 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2261 This->ddraw_fullscreen = fullscreen;
2264 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2265 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2266 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2268 * There is no way to deactivate thread safety once it is enabled.
2270 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2273 /*For now just store the flag(needed in case of ddraw) */
2274 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2279 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2281 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2283 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2286 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2288 /* Resize the screen even without a window:
2289 * The app could have unset it with SetCooperativeLevel, but not called
2290 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2291 * but we don't have any hwnd
2294 memset(&devmode, 0, sizeof(devmode));
2295 devmode.dmSize = sizeof(devmode);
2296 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2297 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2298 devmode.dmPelsWidth = pMode->Width;
2299 devmode.dmPelsHeight = pMode->Height;
2301 devmode.dmDisplayFrequency = pMode->RefreshRate;
2302 if (pMode->RefreshRate != 0) {
2303 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2306 /* Only change the mode if necessary */
2307 if( (This->ddraw_width == pMode->Width) &&
2308 (This->ddraw_height == pMode->Height) &&
2309 (This->ddraw_format == pMode->Format) &&
2310 (pMode->RefreshRate == 0) ) {
2314 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2315 if (ret != DISP_CHANGE_SUCCESSFUL) {
2316 if(devmode.dmDisplayFrequency != 0) {
2317 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2318 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2319 devmode.dmDisplayFrequency = 0;
2320 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2322 if(ret != DISP_CHANGE_SUCCESSFUL) {
2323 return WINED3DERR_NOTAVAILABLE;
2327 /* Store the new values */
2328 This->ddraw_width = pMode->Width;
2329 This->ddraw_height = pMode->Height;
2330 This->ddraw_format = pMode->Format;
2332 /* Only do this with a window of course */
2333 if(This->ddraw_window)
2334 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2336 /* And finally clip mouse to our screen */
2337 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2338 ClipCursor(&clip_rc);
2343 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2345 *ppD3D= This->wineD3D;
2346 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2347 IWineD3D_AddRef(*ppD3D);
2351 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2354 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2355 (This->adapter->TextureRam/(1024*1024)),
2356 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2357 /* return simulated texture memory left */
2358 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2366 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2369 /* Update the current state block */
2370 This->updateStateBlock->changed.fvf = TRUE;
2372 if(This->updateStateBlock->fvf == fvf) {
2373 TRACE("Application is setting the old fvf over, nothing to do\n");
2377 This->updateStateBlock->fvf = fvf;
2378 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2384 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2386 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2387 *pfvf = This->stateBlock->fvf;
2392 * Get / Set Stream Source
2394 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2396 IWineD3DVertexBuffer *oldSrc;
2398 if (StreamNumber >= MAX_STREAMS) {
2399 WARN("Stream out of range %d\n", StreamNumber);
2400 return WINED3DERR_INVALIDCALL;
2401 } else if(OffsetInBytes & 0x3) {
2402 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2403 return WINED3DERR_INVALIDCALL;
2406 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2407 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2409 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2411 if(oldSrc == pStreamData &&
2412 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2413 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2414 TRACE("Application is setting the old values over, nothing to do\n");
2418 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2420 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2421 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2424 /* Handle recording of state blocks */
2425 if (This->isRecordingState) {
2426 TRACE("Recording... not performing anything\n");
2427 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2428 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2432 /* Need to do a getParent and pass the references up */
2433 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2434 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2435 so for now, just count internally */
2436 if (pStreamData != NULL) {
2437 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2438 InterlockedIncrement(&vbImpl->bindCount);
2439 IWineD3DVertexBuffer_AddRef(pStreamData);
2441 if (oldSrc != NULL) {
2442 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2443 IWineD3DVertexBuffer_Release(oldSrc);
2446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2454 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2455 This->stateBlock->streamSource[StreamNumber],
2456 This->stateBlock->streamOffset[StreamNumber],
2457 This->stateBlock->streamStride[StreamNumber]);
2459 if (StreamNumber >= MAX_STREAMS) {
2460 WARN("Stream out of range %d\n", StreamNumber);
2461 return WINED3DERR_INVALIDCALL;
2463 *pStream = This->stateBlock->streamSource[StreamNumber];
2464 *pStride = This->stateBlock->streamStride[StreamNumber];
2466 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2469 if (*pStream != NULL) {
2470 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2475 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2477 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2478 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2480 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2481 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2483 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2484 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2486 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2487 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2488 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2494 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2497 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2498 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2500 TRACE("(%p) : returning %d\n", This, *Divider);
2506 * Get / Set & Multiply Transform
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2511 /* Most of this routine, comments included copied from ddraw tree initially: */
2512 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2514 /* Handle recording of state blocks */
2515 if (This->isRecordingState) {
2516 TRACE("Recording... not performing anything\n");
2517 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2518 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2523 * If the new matrix is the same as the current one,
2524 * we cut off any further processing. this seems to be a reasonable
2525 * optimization because as was noticed, some apps (warcraft3 for example)
2526 * tend towards setting the same matrix repeatedly for some reason.
2528 * From here on we assume that the new matrix is different, wherever it matters.
2530 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2531 TRACE("The app is setting the same matrix over again\n");
2534 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2538 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2539 where ViewMat = Camera space, WorldMat = world space.
2541 In OpenGL, camera and world space is combined into GL_MODELVIEW
2542 matrix. The Projection matrix stay projection matrix.
2545 /* Capture the times we can just ignore the change for now */
2546 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2547 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2548 /* Handled by the state manager */
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2555 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2557 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2558 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2562 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2563 WINED3DMATRIX *mat = NULL;
2566 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2567 * below means it will be recorded in a state block change, but it
2568 * works regardless where it is recorded.
2569 * If this is found to be wrong, change to StateBlock.
2571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2572 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2574 if (State < HIGHEST_TRANSFORMSTATE)
2576 mat = &This->updateStateBlock->transforms[State];
2578 FIXME("Unhandled transform state!!\n");
2581 multiply_matrix(&temp, mat, pMatrix);
2583 /* Apply change via set transform - will reapply to eg. lights this way */
2584 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2590 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2591 you can reference any indexes you want as long as that number max are enabled at any
2592 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2593 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2594 but when recording, just build a chain pretty much of commands to be replayed. */
2596 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2598 PLIGHTINFOEL *object = NULL;
2599 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2603 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2605 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2609 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2610 return WINED3DERR_INVALIDCALL;
2613 switch(pLight->Type) {
2614 case WINED3DLIGHT_POINT:
2615 case WINED3DLIGHT_SPOT:
2616 case WINED3DLIGHT_PARALLELPOINT:
2617 case WINED3DLIGHT_GLSPOT:
2618 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2621 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2622 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2623 return WINED3DERR_INVALIDCALL;
2627 case WINED3DLIGHT_DIRECTIONAL:
2628 /* Ignores attenuation */
2632 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2633 return WINED3DERR_INVALIDCALL;
2636 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2637 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2638 if(object->OriginalIndex == Index) break;
2643 TRACE("Adding new light\n");
2644 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2646 ERR("Out of memory error when allocating a light\n");
2647 return E_OUTOFMEMORY;
2649 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2650 object->glIndex = -1;
2651 object->OriginalIndex = Index;
2652 object->changed = TRUE;
2655 /* Initialize the object */
2656 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,
2657 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2658 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2659 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2660 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2661 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2662 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2664 /* Save away the information */
2665 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2667 switch (pLight->Type) {
2668 case WINED3DLIGHT_POINT:
2670 object->lightPosn[0] = pLight->Position.x;
2671 object->lightPosn[1] = pLight->Position.y;
2672 object->lightPosn[2] = pLight->Position.z;
2673 object->lightPosn[3] = 1.0f;
2674 object->cutoff = 180.0f;
2678 case WINED3DLIGHT_DIRECTIONAL:
2680 object->lightPosn[0] = -pLight->Direction.x;
2681 object->lightPosn[1] = -pLight->Direction.y;
2682 object->lightPosn[2] = -pLight->Direction.z;
2683 object->lightPosn[3] = 0.0;
2684 object->exponent = 0.0f;
2685 object->cutoff = 180.0f;
2688 case WINED3DLIGHT_SPOT:
2690 object->lightPosn[0] = pLight->Position.x;
2691 object->lightPosn[1] = pLight->Position.y;
2692 object->lightPosn[2] = pLight->Position.z;
2693 object->lightPosn[3] = 1.0;
2696 object->lightDirn[0] = pLight->Direction.x;
2697 object->lightDirn[1] = pLight->Direction.y;
2698 object->lightDirn[2] = pLight->Direction.z;
2699 object->lightDirn[3] = 1.0;
2702 * opengl-ish and d3d-ish spot lights use too different models for the
2703 * light "intensity" as a function of the angle towards the main light direction,
2704 * so we only can approximate very roughly.
2705 * however spot lights are rather rarely used in games (if ever used at all).
2706 * furthermore if still used, probably nobody pays attention to such details.
2708 if (pLight->Falloff == 0) {
2709 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2710 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2711 * will always be 1.0 for both of them, and we don't have to care for the
2712 * rest of the rather complex calculation
2714 object->exponent = 0;
2716 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2717 if (rho < 0.0001) rho = 0.0001f;
2718 object->exponent = -0.3/log(cos(rho/2));
2720 if (object->exponent > 128.0) {
2721 object->exponent = 128.0;
2723 object->cutoff = pLight->Phi*90/M_PI;
2729 FIXME("Unrecognized light type %d\n", pLight->Type);
2732 /* Update the live definitions if the light is currently assigned a glIndex */
2733 if (object->glIndex != -1 && !This->isRecordingState) {
2734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2739 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2740 PLIGHTINFOEL *lightInfo = NULL;
2741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2742 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2744 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2746 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2747 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2748 if(lightInfo->OriginalIndex == Index) break;
2752 if (lightInfo == NULL) {
2753 TRACE("Light information requested but light not defined\n");
2754 return WINED3DERR_INVALIDCALL;
2757 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2762 * Get / Set Light Enable
2763 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2765 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2766 PLIGHTINFOEL *lightInfo = NULL;
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2770 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2772 /* Tests show true = 128...not clear why */
2773 Enable = Enable? 128: 0;
2775 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2776 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2777 if(lightInfo->OriginalIndex == Index) break;
2780 TRACE("Found light: %p\n", lightInfo);
2782 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2783 if (lightInfo == NULL) {
2785 TRACE("Light enabled requested but light not defined, so defining one!\n");
2786 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2788 /* Search for it again! Should be fairly quick as near head of list */
2789 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2790 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2791 if(lightInfo->OriginalIndex == Index) break;
2794 if (lightInfo == NULL) {
2795 FIXME("Adding default lights has failed dismally\n");
2796 return WINED3DERR_INVALIDCALL;
2800 lightInfo->enabledChanged = TRUE;
2802 if(lightInfo->glIndex != -1) {
2803 if(!This->isRecordingState) {
2804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2807 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2808 lightInfo->glIndex = -1;
2810 TRACE("Light already disabled, nothing to do\n");
2812 lightInfo->enabled = FALSE;
2814 lightInfo->enabled = TRUE;
2815 if (lightInfo->glIndex != -1) {
2817 TRACE("Nothing to do as light was enabled\n");
2820 /* Find a free gl light */
2821 for(i = 0; i < This->maxConcurrentLights; i++) {
2822 if(This->stateBlock->activeLights[i] == NULL) {
2823 This->stateBlock->activeLights[i] = lightInfo;
2824 lightInfo->glIndex = i;
2828 if(lightInfo->glIndex == -1) {
2829 /* Our tests show that Windows returns D3D_OK in this situation, even with
2830 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2831 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2832 * as well for those lights.
2834 * TODO: Test how this affects rendering
2836 FIXME("Too many concurrently active lights\n");
2840 /* i == lightInfo->glIndex */
2841 if(!This->isRecordingState) {
2842 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2850 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2852 PLIGHTINFOEL *lightInfo = NULL;
2853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2855 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2856 TRACE("(%p) : for idx(%d)\n", This, Index);
2858 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2859 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2860 if(lightInfo->OriginalIndex == Index) break;
2864 if (lightInfo == NULL) {
2865 TRACE("Light enabled state requested but light not defined\n");
2866 return WINED3DERR_INVALIDCALL;
2868 /* true is 128 according to SetLightEnable */
2869 *pEnable = lightInfo->enabled ? 128 : 0;
2874 * Get / Set Clip Planes
2876 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2877 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2878 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2880 /* Validate Index */
2881 if (Index >= GL_LIMITS(clipplanes)) {
2882 TRACE("Application has requested clipplane this device doesn't support\n");
2883 return WINED3DERR_INVALIDCALL;
2886 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2888 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2889 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2890 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2891 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2892 TRACE("Application is setting old values over, nothing to do\n");
2896 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2897 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2898 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2899 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2901 /* Handle recording of state blocks */
2902 if (This->isRecordingState) {
2903 TRACE("Recording... not performing anything\n");
2907 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2912 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2914 TRACE("(%p) : for idx %d\n", This, Index);
2916 /* Validate Index */
2917 if (Index >= GL_LIMITS(clipplanes)) {
2918 TRACE("Application has requested clipplane this device doesn't support\n");
2919 return WINED3DERR_INVALIDCALL;
2922 pPlane[0] = This->stateBlock->clipplane[Index][0];
2923 pPlane[1] = This->stateBlock->clipplane[Index][1];
2924 pPlane[2] = This->stateBlock->clipplane[Index][2];
2925 pPlane[3] = This->stateBlock->clipplane[Index][3];
2930 * Get / Set Clip Plane Status
2931 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2933 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 FIXME("(%p) : stub\n", This);
2936 if (NULL == pClipStatus) {
2937 return WINED3DERR_INVALIDCALL;
2939 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2940 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2944 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2945 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2946 FIXME("(%p) : stub\n", This);
2947 if (NULL == pClipStatus) {
2948 return WINED3DERR_INVALIDCALL;
2950 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2951 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2956 * Get / Set Material
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 This->updateStateBlock->changed.material = TRUE;
2962 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2964 /* Handle recording of state blocks */
2965 if (This->isRecordingState) {
2966 TRACE("Recording... not performing anything\n");
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2974 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2976 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2977 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2978 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2979 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2980 pMaterial->Ambient.b, pMaterial->Ambient.a);
2981 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2982 pMaterial->Specular.b, pMaterial->Specular.a);
2983 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2984 pMaterial->Emissive.b, pMaterial->Emissive.a);
2985 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2993 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
2994 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2995 IWineD3DIndexBuffer *oldIdxs;
2997 TRACE("(%p) : Setting to %p\n", This, pIndexData);
2998 oldIdxs = This->updateStateBlock->pIndexData;
3000 This->updateStateBlock->changed.indices = TRUE;
3001 This->updateStateBlock->pIndexData = pIndexData;
3003 /* Handle recording of state blocks */
3004 if (This->isRecordingState) {
3005 TRACE("Recording... not performing anything\n");
3006 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3007 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3011 if(oldIdxs != pIndexData) {
3012 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3013 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3014 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3019 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3022 *ppIndexData = This->stateBlock->pIndexData;
3024 /* up ref count on ppindexdata */
3026 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3027 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3029 TRACE("(%p) No index data set\n", This);
3031 TRACE("Returning %p\n", *ppIndexData);
3036 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3037 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3039 TRACE("(%p)->(%d)\n", This, BaseIndex);
3041 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3042 TRACE("Application is setting the old value over, nothing to do\n");
3046 This->updateStateBlock->baseVertexIndex = BaseIndex;
3048 if (This->isRecordingState) {
3049 TRACE("Recording... not performing anything\n");
3052 /* The base vertex index affects the stream sources */
3053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3057 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3059 TRACE("(%p) : base_index %p\n", This, base_index);
3061 *base_index = This->stateBlock->baseVertexIndex;
3063 TRACE("Returning %u\n", *base_index);
3069 * Get / Set Viewports
3071 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3072 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 TRACE("(%p)\n", This);
3075 This->updateStateBlock->changed.viewport = TRUE;
3076 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3078 /* Handle recording of state blocks */
3079 if (This->isRecordingState) {
3080 TRACE("Recording... not performing anything\n");
3084 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3085 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3092 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3093 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3094 TRACE("(%p)\n", This);
3095 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3100 * Get / Set Render States
3101 * TODO: Verify against dx9 definitions
3103 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 DWORD oldValue = This->stateBlock->renderState[State];
3108 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3110 This->updateStateBlock->changed.renderState[State] = TRUE;
3111 This->updateStateBlock->renderState[State] = Value;
3113 /* Handle recording of state blocks */
3114 if (This->isRecordingState) {
3115 TRACE("Recording... not performing anything\n");
3119 /* Compared here and not before the assignment to allow proper stateblock recording */
3120 if(Value == oldValue) {
3121 TRACE("Application is setting the old value over, nothing to do\n");
3123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3129 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3132 *pValue = This->stateBlock->renderState[State];
3137 * Get / Set Sampler States
3138 * TODO: Verify against dx9 definitions
3141 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3145 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3146 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3148 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3149 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3152 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3153 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3154 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3157 * SetSampler is designed to allow for more than the standard up to 8 textures
3158 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3159 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3161 * http://developer.nvidia.com/object/General_FAQ.html#t6
3163 * There are two new settings for GForce
3165 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3166 * and the texture one:
3167 * GL_MAX_TEXTURE_COORDS_ARB.
3168 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3171 oldValue = This->stateBlock->samplerState[Sampler][Type];
3172 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3173 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3175 /* Handle recording of state blocks */
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3181 if(oldValue == Value) {
3182 TRACE("Application is setting the old value over, nothing to do\n");
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3195 This, Sampler, debug_d3dsamplerstate(Type), Type);
3197 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3198 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3201 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3202 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3203 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3205 *Value = This->stateBlock->samplerState[Sampler][Type];
3206 TRACE("(%p) : Returning %#x\n", This, *Value);
3211 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3214 This->updateStateBlock->changed.scissorRect = TRUE;
3215 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3216 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3219 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3221 if(This->isRecordingState) {
3222 TRACE("Recording... not performing anything\n");
3226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3231 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3232 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3234 *pRect = This->updateStateBlock->scissorRect;
3235 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3239 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3241 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3243 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3245 This->updateStateBlock->vertexDecl = pDecl;
3246 This->updateStateBlock->changed.vertexDecl = TRUE;
3248 if (This->isRecordingState) {
3249 TRACE("Recording... not performing anything\n");
3251 } else if(pDecl == oldDecl) {
3252 /* Checked after the assignment to allow proper stateblock recording */
3253 TRACE("Application is setting the old declaration over, nothing to do\n");
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3261 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3262 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3264 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3266 *ppDecl = This->stateBlock->vertexDecl;
3267 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3275 This->updateStateBlock->vertexShader = pShader;
3276 This->updateStateBlock->changed.vertexShader = TRUE;
3278 if (This->isRecordingState) {
3279 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3280 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3281 TRACE("Recording... not performing anything\n");
3283 } else if(oldShader == pShader) {
3284 /* Checked here to allow proper stateblock recording */
3285 TRACE("App is setting the old shader over, nothing to do\n");
3289 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3290 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3291 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3298 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3301 if (NULL == ppShader) {
3302 return WINED3DERR_INVALIDCALL;
3304 *ppShader = This->stateBlock->vertexShader;
3305 if( NULL != *ppShader)
3306 IWineD3DVertexShader_AddRef(*ppShader);
3308 TRACE("(%p) : returning %p\n", This, *ppShader);
3312 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3313 IWineD3DDevice *iface,
3315 CONST BOOL *srcData,
3318 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3319 int i, cnt = min(count, MAX_CONST_B - start);
3321 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3322 iface, srcData, start, count);
3324 if (srcData == NULL || cnt < 0)
3325 return WINED3DERR_INVALIDCALL;
3327 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3328 for (i = 0; i < cnt; i++)
3329 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3331 for (i = start; i < cnt + start; ++i) {
3332 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3335 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3340 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3341 IWineD3DDevice *iface,
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 int cnt = min(count, MAX_CONST_B - start);
3349 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3350 iface, dstData, start, count);
3352 if (dstData == NULL || cnt < 0)
3353 return WINED3DERR_INVALIDCALL;
3355 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3359 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3360 IWineD3DDevice *iface,
3365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3366 int i, cnt = min(count, MAX_CONST_I - start);
3368 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3369 iface, srcData, start, count);
3371 if (srcData == NULL || cnt < 0)
3372 return WINED3DERR_INVALIDCALL;
3374 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3375 for (i = 0; i < cnt; i++)
3376 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3377 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3379 for (i = start; i < cnt + start; ++i) {
3380 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3388 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3389 IWineD3DDevice *iface,
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3395 int cnt = min(count, MAX_CONST_I - start);
3397 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3398 iface, dstData, start, count);
3400 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3401 return WINED3DERR_INVALIDCALL;
3403 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3407 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3408 IWineD3DDevice *iface,
3410 CONST float *srcData,
3413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3416 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3417 iface, srcData, start, count);
3419 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3420 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3421 return WINED3DERR_INVALIDCALL;
3423 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3425 for (i = 0; i < count; i++)
3426 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3427 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3430 for (i = start; i < count + start; ++i) {
3431 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3432 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3433 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3434 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3435 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3437 ptr->idx[ptr->count++] = i;
3438 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3448 IWineD3DDevice *iface,
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3456 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3457 iface, dstData, start, count);
3459 if (dstData == NULL || cnt < 0)
3460 return WINED3DERR_INVALIDCALL;
3462 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3466 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3468 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3473 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3474 int i = This->rev_tex_unit_map[unit];
3475 int j = This->texUnitMap[stage];
3477 This->texUnitMap[stage] = unit;
3478 if (i != -1 && i != stage) {
3479 This->texUnitMap[i] = -1;
3482 This->rev_tex_unit_map[unit] = stage;
3483 if (j != -1 && j != unit) {
3484 This->rev_tex_unit_map[j] = -1;
3488 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3491 for (i = 0; i < MAX_TEXTURES; ++i) {
3492 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3493 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3494 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3495 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3496 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3497 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3498 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3499 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3501 if (color_op == WINED3DTOP_DISABLE) {
3502 /* Not used, and disable higher stages */
3503 while (i < MAX_TEXTURES) {
3504 This->fixed_function_usage_map[i] = FALSE;
3510 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3511 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3512 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3513 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3514 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3515 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3516 This->fixed_function_usage_map[i] = TRUE;
3518 This->fixed_function_usage_map[i] = FALSE;
3521 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3522 This->fixed_function_usage_map[i+1] = TRUE;
3527 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3530 device_update_fixed_function_usage_map(This);
3532 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3533 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3534 if (!This->fixed_function_usage_map[i]) continue;
3536 if (This->texUnitMap[i] != i) {
3537 device_map_stage(This, i, i);
3538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3539 markTextureStagesDirty(This, i);
3545 /* Now work out the mapping */
3547 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3548 if (!This->fixed_function_usage_map[i]) continue;
3550 if (This->texUnitMap[i] != tex) {
3551 device_map_stage(This, i, tex);
3552 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3553 markTextureStagesDirty(This, i);
3560 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3561 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3564 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3565 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3566 device_map_stage(This, i, i);
3567 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3568 if (i < MAX_TEXTURES) {
3569 markTextureStagesDirty(This, i);
3575 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3576 int current_mapping = This->rev_tex_unit_map[unit];
3578 if (current_mapping == -1) {
3579 /* Not currently used */
3583 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3584 /* Used by a fragment sampler */
3586 if (!pshader_sampler_tokens) {
3587 /* No pixel shader, check fixed function */
3588 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3591 /* Pixel shader, check the shader's sampler map */
3592 return !pshader_sampler_tokens[current_mapping];
3595 /* Used by a vertex sampler */
3596 return !vshader_sampler_tokens[current_mapping];
3599 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3600 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3601 DWORD *pshader_sampler_tokens = NULL;
3602 int start = GL_LIMITS(combined_samplers) - 1;
3606 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3608 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3609 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3610 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3613 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3614 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3615 if (vshader_sampler_tokens[i]) {
3616 if (This->texUnitMap[vsampler_idx] != -1) {
3617 /* Already mapped somewhere */
3621 while (start >= 0) {
3622 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3623 device_map_stage(This, vsampler_idx, start);
3624 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3636 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3637 BOOL vs = use_vs(This);
3638 BOOL ps = use_ps(This);
3641 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3642 * that would be really messy and require shader recompilation
3643 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3644 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3647 device_map_psamplers(This);
3649 device_map_fixed_function_samplers(This);
3653 device_map_vsamplers(This, ps);
3657 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3659 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3660 This->updateStateBlock->pixelShader = pShader;
3661 This->updateStateBlock->changed.pixelShader = TRUE;
3663 /* Handle recording of state blocks */
3664 if (This->isRecordingState) {
3665 TRACE("Recording... not performing anything\n");
3668 if (This->isRecordingState) {
3669 TRACE("Recording... not performing anything\n");
3670 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3671 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3675 if(pShader == oldShader) {
3676 TRACE("App is setting the old pixel shader over, nothing to do\n");
3680 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3681 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3683 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3689 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3692 if (NULL == ppShader) {
3693 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3694 return WINED3DERR_INVALIDCALL;
3697 *ppShader = This->stateBlock->pixelShader;
3698 if (NULL != *ppShader) {
3699 IWineD3DPixelShader_AddRef(*ppShader);
3701 TRACE("(%p) : returning %p\n", This, *ppShader);
3705 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3706 IWineD3DDevice *iface,
3708 CONST BOOL *srcData,
3711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3712 int i, cnt = min(count, MAX_CONST_B - start);
3714 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3715 iface, srcData, start, count);
3717 if (srcData == NULL || cnt < 0)
3718 return WINED3DERR_INVALIDCALL;
3720 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3721 for (i = 0; i < cnt; i++)
3722 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3724 for (i = start; i < cnt + start; ++i) {
3725 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3728 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3733 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3734 IWineD3DDevice *iface,
3739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3740 int cnt = min(count, MAX_CONST_B - start);
3742 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3743 iface, dstData, start, count);
3745 if (dstData == NULL || cnt < 0)
3746 return WINED3DERR_INVALIDCALL;
3748 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3752 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3753 IWineD3DDevice *iface,
3758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3759 int i, cnt = min(count, MAX_CONST_I - start);
3761 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3762 iface, srcData, start, count);
3764 if (srcData == NULL || cnt < 0)
3765 return WINED3DERR_INVALIDCALL;
3767 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3768 for (i = 0; i < cnt; i++)
3769 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3770 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3772 for (i = start; i < cnt + start; ++i) {
3773 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3781 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3782 IWineD3DDevice *iface,
3787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3788 int cnt = min(count, MAX_CONST_I - start);
3790 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3791 iface, dstData, start, count);
3793 if (dstData == NULL || cnt < 0)
3794 return WINED3DERR_INVALIDCALL;
3796 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3800 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3801 IWineD3DDevice *iface,
3803 CONST float *srcData,
3806 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3809 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3810 iface, srcData, start, count);
3812 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3813 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3814 return WINED3DERR_INVALIDCALL;
3816 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3818 for (i = 0; i < count; i++)
3819 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3820 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3823 for (i = start; i < count + start; ++i) {
3824 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3825 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3826 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3827 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3828 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3830 ptr->idx[ptr->count++] = i;
3831 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3835 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3840 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3841 IWineD3DDevice *iface,
3846 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3847 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3849 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3850 iface, dstData, start, count);
3852 if (dstData == NULL || cnt < 0)
3853 return WINED3DERR_INVALIDCALL;
3855 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3859 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3861 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3862 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3864 DWORD DestFVF = dest->fvf;
3866 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3870 if (lpStrideData->u.s.normal.lpData) {
3871 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3874 if (lpStrideData->u.s.position.lpData == NULL) {
3875 ERR("Source has no position mask\n");
3876 return WINED3DERR_INVALIDCALL;
3879 /* We might access VBOs from this code, so hold the lock */
3882 if (dest->resource.allocatedMemory == NULL) {
3883 /* This may happen if we do direct locking into a vbo. Unlikely,
3884 * but theoretically possible(ddraw processvertices test)
3886 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3887 if(!dest->resource.allocatedMemory) {
3889 ERR("Out of memory\n");
3890 return E_OUTOFMEMORY;
3894 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3895 checkGLcall("glBindBufferARB");
3896 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3898 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3900 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3901 checkGLcall("glUnmapBufferARB");
3905 /* Get a pointer into the destination vbo(create one if none exists) and
3906 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3908 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3909 dest->Flags |= VBFLAG_CREATEVBO;
3910 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
3914 unsigned char extrabytes = 0;
3915 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3916 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3917 * this may write 4 extra bytes beyond the area that should be written
3919 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3920 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3921 if(!dest_conv_addr) {
3922 ERR("Out of memory\n");
3923 /* Continue without storing converted vertices */
3925 dest_conv = dest_conv_addr;
3929 * a) WINED3DRS_CLIPPING is enabled
3930 * b) WINED3DVOP_CLIP is passed
3932 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3933 static BOOL warned = FALSE;
3935 * The clipping code is not quite correct. Some things need
3936 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3937 * so disable clipping for now.
3938 * (The graphics in Half-Life are broken, and my processvertices
3939 * test crashes with IDirect3DDevice3)
3945 FIXME("Clipping is broken and disabled for now\n");
3947 } else doClip = FALSE;
3948 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3950 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3953 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3954 WINED3DTS_PROJECTION,
3956 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3957 WINED3DTS_WORLDMATRIX(0),
3960 TRACE("View mat:\n");
3961 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);
3962 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);
3963 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);
3964 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);
3966 TRACE("Proj mat:\n");
3967 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);
3968 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);
3969 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);
3970 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);
3972 TRACE("World mat:\n");
3973 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);
3974 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);
3975 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);
3976 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);
3978 /* Get the viewport */
3979 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3980 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3981 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3983 multiply_matrix(&mat,&view_mat,&world_mat);
3984 multiply_matrix(&mat,&proj_mat,&mat);
3986 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3988 for (i = 0; i < dwCount; i+= 1) {
3989 unsigned int tex_index;
3991 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3992 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3993 /* The position first */
3995 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
3997 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
3999 /* Multiplication with world, view and projection matrix */
4000 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);
4001 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);
4002 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);
4003 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);
4005 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4007 /* WARNING: The following things are taken from d3d7 and were not yet checked
4008 * against d3d8 or d3d9!
4011 /* Clipping conditions: From
4012 * http://msdn.microsoft.com/archive/default.asp?url=/archive/en-us/directx9_c/directx/graphics/programmingguide/fixedfunction/viewportsclipping/clippingvolumes.asp
4014 * A vertex is clipped if it does not match the following requirements
4018 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4020 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4021 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4026 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4027 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4030 /* "Normal" viewport transformation (not clipped)
4031 * 1) The values are divided by rhw
4032 * 2) The y axis is negative, so multiply it with -1
4033 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4034 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4035 * 4) Multiply x with Width/2 and add Width/2
4036 * 5) The same for the height
4037 * 6) Add the viewpoint X and Y to the 2D coordinates and
4038 * The minimum Z value to z
4039 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4041 * Well, basically it's simply a linear transformation into viewport
4053 z *= vp.MaxZ - vp.MinZ;
4055 x += vp.Width / 2 + vp.X;
4056 y += vp.Height / 2 + vp.Y;
4061 /* That vertex got clipped
4062 * Contrary to OpenGL it is not dropped completely, it just
4063 * undergoes a different calculation.
4065 TRACE("Vertex got clipped\n");
4072 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4073 * outside of the main vertex buffer memory. That needs some more
4078 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4081 ( (float *) dest_ptr)[0] = x;
4082 ( (float *) dest_ptr)[1] = y;
4083 ( (float *) dest_ptr)[2] = z;
4084 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4086 dest_ptr += 3 * sizeof(float);
4088 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4089 dest_ptr += sizeof(float);
4094 ( (float *) dest_conv)[0] = x * w;
4095 ( (float *) dest_conv)[1] = y * w;
4096 ( (float *) dest_conv)[2] = z * w;
4097 ( (float *) dest_conv)[3] = w;
4099 dest_conv += 3 * sizeof(float);
4101 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4102 dest_conv += sizeof(float);
4106 if (DestFVF & WINED3DFVF_PSIZE) {
4107 dest_ptr += sizeof(DWORD);
4108 if(dest_conv) dest_conv += sizeof(DWORD);
4110 if (DestFVF & WINED3DFVF_NORMAL) {
4112 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4113 /* AFAIK this should go into the lighting information */
4114 FIXME("Didn't expect the destination to have a normal\n");
4115 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4117 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4121 if (DestFVF & WINED3DFVF_DIFFUSE) {
4123 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4125 static BOOL warned = FALSE;
4128 ERR("No diffuse color in source, but destination has one\n");
4132 *( (DWORD *) dest_ptr) = 0xffffffff;
4133 dest_ptr += sizeof(DWORD);
4136 *( (DWORD *) dest_conv) = 0xffffffff;
4137 dest_conv += sizeof(DWORD);
4141 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4143 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4144 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4145 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4146 dest_conv += sizeof(DWORD);
4151 if (DestFVF & WINED3DFVF_SPECULAR) {
4152 /* What's the color value in the feedback buffer? */
4154 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4156 static BOOL warned = FALSE;
4159 ERR("No specular color in source, but destination has one\n");
4163 *( (DWORD *) dest_ptr) = 0xFF000000;
4164 dest_ptr += sizeof(DWORD);
4167 *( (DWORD *) dest_conv) = 0xFF000000;
4168 dest_conv += sizeof(DWORD);
4172 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4174 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4175 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4176 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4177 dest_conv += sizeof(DWORD);
4182 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4184 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4185 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4187 ERR("No source texture, but destination requests one\n");
4188 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4189 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4192 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4194 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4201 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4202 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4203 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4204 dwCount * get_flexible_vertex_size(DestFVF),
4206 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4207 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4214 #undef copy_and_next
4216 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4218 WineDirect3DVertexStridedData strided;
4219 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4220 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4223 ERR("Output vertex declaration not implemented yet\n");
4226 /* Need any context to write to the vbo. */
4227 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4229 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4230 * control the streamIsUP flag, thus restore it afterwards.
4232 This->stateBlock->streamIsUP = FALSE;
4233 memset(&strided, 0, sizeof(strided));
4234 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4235 This->stateBlock->streamIsUP = streamWasUP;
4237 if(vbo || SrcStartIndex) {
4239 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4240 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4242 * Also get the start index in, but only loop over all elements if there's something to add at all.
4244 #define FIXSRC(type) \
4245 if(strided.u.s.type.VBO) { \
4246 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4247 strided.u.s.type.VBO = 0; \
4248 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4250 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4254 if(strided.u.s.type.lpData) { \
4255 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4258 FIXSRC(blendWeights);
4259 FIXSRC(blendMatrixIndices);
4264 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4265 FIXSRC(texCoords[i]);
4278 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4282 * Get / Set Texture Stage States
4283 * TODO: Verify against dx9 definitions
4285 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4287 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4289 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4291 if (Stage >= MAX_TEXTURES) {
4292 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4296 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4297 This->updateStateBlock->textureState[Stage][Type] = Value;
4299 if (This->isRecordingState) {
4300 TRACE("Recording... not performing anything\n");
4304 /* Checked after the assignments to allow proper stateblock recording */
4305 if(oldValue == Value) {
4306 TRACE("App is setting the old value over, nothing to do\n");
4310 if(Stage > This->stateBlock->lowest_disabled_stage &&
4311 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4312 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4313 * Changes in other states are important on disabled stages too
4318 if(Type == WINED3DTSS_COLOROP) {
4321 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4322 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4323 * they have to be disabled
4325 * The current stage is dirtified below.
4327 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4328 TRACE("Additionally dirtifying stage %d\n", i);
4329 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4331 This->stateBlock->lowest_disabled_stage = Stage;
4332 TRACE("New lowest disabled: %d\n", Stage);
4333 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4334 /* Previously disabled stage enabled. Stages above it may need enabling
4335 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4336 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4338 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4341 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4342 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4345 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4348 This->stateBlock->lowest_disabled_stage = i;
4349 TRACE("New lowest disabled: %d\n", i);
4351 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4352 /* TODO: Built a stage -> texture unit mapping for register combiners */
4356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4361 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4363 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4364 *pValue = This->updateStateBlock->textureState[Stage][Type];
4371 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4372 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4373 IWineD3DBaseTexture *oldTexture;
4375 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4377 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4378 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4381 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4382 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4383 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4386 oldTexture = This->updateStateBlock->textures[Stage];
4388 if(pTexture != NULL) {
4389 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4391 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4392 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4393 return WINED3DERR_INVALIDCALL;
4395 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4398 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4399 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4401 This->updateStateBlock->changed.textures[Stage] = TRUE;
4402 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4403 This->updateStateBlock->textures[Stage] = pTexture;
4405 /* Handle recording of state blocks */
4406 if (This->isRecordingState) {
4407 TRACE("Recording... not performing anything\n");
4411 if(oldTexture == pTexture) {
4412 TRACE("App is setting the same texture again, nothing to do\n");
4416 /** NOTE: MSDN says that setTexture increases the reference count,
4417 * and that the application must set the texture back to null (or have a leaky application),
4418 * This means we should pass the refcount up to the parent
4419 *******************************/
4420 if (NULL != This->updateStateBlock->textures[Stage]) {
4421 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4422 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4424 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4425 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4426 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4427 * so the COLOROP and ALPHAOP have to be dirtified.
4429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4430 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4432 if(bindCount == 1) {
4433 new->baseTexture.sampler = Stage;
4435 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4439 if (NULL != oldTexture) {
4440 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4441 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4443 IWineD3DBaseTexture_Release(oldTexture);
4444 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4445 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4449 if(bindCount && old->baseTexture.sampler == Stage) {
4451 /* Have to do a search for the other sampler(s) where the texture is bound to
4452 * Shouldn't happen as long as apps bind a texture only to one stage
4454 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4455 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4456 if(This->updateStateBlock->textures[i] == oldTexture) {
4457 old->baseTexture.sampler = i;
4464 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4469 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4472 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4474 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4475 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4478 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4479 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4480 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4483 *ppTexture=This->stateBlock->textures[Stage];
4485 IWineD3DBaseTexture_AddRef(*ppTexture);
4487 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4495 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4496 IWineD3DSurface **ppBackBuffer) {
4497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4498 IWineD3DSwapChain *swapChain;
4501 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4503 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4504 if (hr == WINED3D_OK) {
4505 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4506 IWineD3DSwapChain_Release(swapChain);
4508 *ppBackBuffer = NULL;
4513 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4515 WARN("(%p) : stub, calling idirect3d for now\n", This);
4516 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4519 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4520 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4521 IWineD3DSwapChain *swapChain;
4524 if(iSwapChain > 0) {
4525 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4526 if (hr == WINED3D_OK) {
4527 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4528 IWineD3DSwapChain_Release(swapChain);
4530 FIXME("(%p) Error getting display mode\n", This);
4533 /* Don't read the real display mode,
4534 but return the stored mode instead. X11 can't change the color
4535 depth, and some apps are pretty angry if they SetDisplayMode from
4536 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4538 Also don't relay to the swapchain because with ddraw it's possible
4539 that there isn't a swapchain at all */
4540 pMode->Width = This->ddraw_width;
4541 pMode->Height = This->ddraw_height;
4542 pMode->Format = This->ddraw_format;
4543 pMode->RefreshRate = 0;
4550 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4552 TRACE("(%p)->(%p)\n", This, hWnd);
4554 if(This->ddraw_fullscreen) {
4555 if(This->ddraw_window && This->ddraw_window != hWnd) {
4556 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4558 if(hWnd && This->ddraw_window != hWnd) {
4559 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4563 This->ddraw_window = hWnd;
4567 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4569 TRACE("(%p)->(%p)\n", This, hWnd);
4571 *hWnd = This->ddraw_window;
4576 * Stateblock related functions
4579 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 IWineD3DStateBlockImpl *object;
4582 HRESULT temp_result;
4585 TRACE("(%p)\n", This);
4587 if (This->isRecordingState) {
4588 return WINED3DERR_INVALIDCALL;
4591 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4592 if (NULL == object ) {
4593 FIXME("(%p)Error allocating memory for stateblock\n", This);
4594 return E_OUTOFMEMORY;
4596 TRACE("(%p) created object %p\n", This, object);
4597 object->wineD3DDevice= This;
4598 /** FIXME: object->parent = parent; **/
4599 object->parent = NULL;
4600 object->blockType = WINED3DSBT_RECORDED;
4602 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4604 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4605 list_init(&object->lightMap[i]);
4608 temp_result = allocate_shader_constants(object);
4609 if (WINED3D_OK != temp_result)
4612 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4613 This->updateStateBlock = object;
4614 This->isRecordingState = TRUE;
4616 TRACE("(%p) recording stateblock %p\n",This , object);
4620 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4625 if (!This->isRecordingState) {
4626 FIXME("(%p) not recording! returning error\n", This);
4627 *ppStateBlock = NULL;
4628 return WINED3DERR_INVALIDCALL;
4631 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4632 if(object->changed.renderState[i]) {
4633 object->contained_render_states[object->num_contained_render_states] = i;
4634 object->num_contained_render_states++;
4637 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4638 if(object->changed.transform[i]) {
4639 object->contained_transform_states[object->num_contained_transform_states] = i;
4640 object->num_contained_transform_states++;
4643 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4644 if(object->changed.vertexShaderConstantsF[i]) {
4645 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4646 object->num_contained_vs_consts_f++;
4649 for(i = 0; i < MAX_CONST_I; i++) {
4650 if(object->changed.vertexShaderConstantsI[i]) {
4651 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4652 object->num_contained_vs_consts_i++;
4655 for(i = 0; i < MAX_CONST_B; i++) {
4656 if(object->changed.vertexShaderConstantsB[i]) {
4657 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4658 object->num_contained_vs_consts_b++;
4661 for(i = 0; i < MAX_CONST_I; i++) {
4662 if(object->changed.pixelShaderConstantsI[i]) {
4663 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4664 object->num_contained_ps_consts_i++;
4667 for(i = 0; i < MAX_CONST_B; i++) {
4668 if(object->changed.pixelShaderConstantsB[i]) {
4669 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4670 object->num_contained_ps_consts_b++;
4673 for(i = 0; i < MAX_TEXTURES; i++) {
4674 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4675 if(object->changed.textureState[i][j]) {
4676 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4677 object->contained_tss_states[object->num_contained_tss_states].state = j;
4678 object->num_contained_tss_states++;
4682 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4683 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4684 if(object->changed.samplerState[i][j]) {
4685 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4686 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4687 object->num_contained_sampler_states++;
4692 *ppStateBlock = (IWineD3DStateBlock*) object;
4693 This->isRecordingState = FALSE;
4694 This->updateStateBlock = This->stateBlock;
4695 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4696 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4697 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4702 * Scene related functions
4704 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4705 /* At the moment we have no need for any functionality at the beginning
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 TRACE("(%p)\n", This);
4711 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4712 return WINED3DERR_INVALIDCALL;
4714 This->inScene = TRUE;
4718 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4720 TRACE("(%p)\n", This);
4722 if(!This->inScene) {
4723 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4724 return WINED3DERR_INVALIDCALL;
4727 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4728 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4731 checkGLcall("glFlush");
4734 This->inScene = FALSE;
4738 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4739 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4740 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4741 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4742 IWineD3DSwapChain *swapChain = NULL;
4744 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4746 TRACE("(%p) Presenting the frame\n", This);
4748 for(i = 0 ; i < swapchains ; i ++) {
4750 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4751 TRACE("presentinng chain %d, %p\n", i, swapChain);
4752 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4753 IWineD3DSwapChain_Release(swapChain);
4759 /* Not called from the VTable (internal subroutine) */
4760 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4761 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4762 float Z, DWORD Stencil) {
4763 GLbitfield glMask = 0;
4765 WINED3DRECT curRect;
4767 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4768 UINT drawable_width, drawable_height;
4769 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4771 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4772 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4773 * for the cleared parts, and the untouched parts.
4775 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4776 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4777 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4778 * checking all this if the dest surface is in the drawable anyway.
4780 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4782 if(vp->X != 0 || vp->Y != 0 ||
4783 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4784 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4787 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4788 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4789 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4790 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4791 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4794 if(Count > 0 && pRects && (
4795 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4796 pRects[0].x2 < target->currentDesc.Width ||
4797 pRects[0].y2 < target->currentDesc.Height)) {
4798 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4805 target->get_drawable_size(target, &drawable_width, &drawable_height);
4807 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4810 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4811 apply_fbo_state((IWineD3DDevice *) This);
4814 /* Only set the values up once, as they are not changing */
4815 if (Flags & WINED3DCLEAR_STENCIL) {
4816 glClearStencil(Stencil);
4817 checkGLcall("glClearStencil");
4818 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4819 glStencilMask(0xFFFFFFFF);
4822 if (Flags & WINED3DCLEAR_ZBUFFER) {
4823 glDepthMask(GL_TRUE);
4825 checkGLcall("glClearDepth");
4826 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4827 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4829 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4830 if(vp->X != 0 || vp->Y != 0 ||
4831 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4832 depth_copy((IWineD3DDevice *) This);
4834 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4835 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4836 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4837 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4838 depth_copy((IWineD3DDevice *) This);
4840 else if(Count > 0 && pRects && (
4841 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4842 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4843 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4844 depth_copy((IWineD3DDevice *) This);
4847 This->depth_copy_state = WINED3D_DCS_INITIAL;
4850 if (Flags & WINED3DCLEAR_TARGET) {
4851 TRACE("Clearing screen with glClear to color %x\n", Color);
4852 glClearColor(D3DCOLOR_R(Color),
4856 checkGLcall("glClearColor");
4858 /* Clear ALL colors! */
4859 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4860 glMask = glMask | GL_COLOR_BUFFER_BIT;
4863 vp_rect.left = vp->X;
4864 vp_rect.top = vp->Y;
4865 vp_rect.right = vp->X + vp->Width;
4866 vp_rect.bottom = vp->Y + vp->Height;
4867 if (!(Count > 0 && pRects)) {
4868 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4869 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4871 if(This->render_offscreen) {
4872 glScissor(vp_rect.left, vp_rect.top,
4873 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4875 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4876 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4878 checkGLcall("glScissor");
4880 checkGLcall("glClear");
4882 /* Now process each rect in turn */
4883 for (i = 0; i < Count; i++) {
4884 /* Note gl uses lower left, width/height */
4885 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4886 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4887 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4889 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4890 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4891 curRect.x1, (target->currentDesc.Height - curRect.y2),
4892 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4894 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4895 * The rectangle is not cleared, no error is returned, but further rectanlges are
4896 * still cleared if they are valid
4898 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4899 TRACE("Rectangle with negative dimensions, ignoring\n");
4903 if(This->render_offscreen) {
4904 glScissor(curRect.x1, curRect.y1,
4905 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4907 glScissor(curRect.x1, drawable_height - curRect.y2,
4908 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4910 checkGLcall("glScissor");
4913 checkGLcall("glClear");
4917 /* Restore the old values (why..?) */
4918 if (Flags & WINED3DCLEAR_STENCIL) {
4919 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4921 if (Flags & WINED3DCLEAR_TARGET) {
4922 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4923 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4924 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4925 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4926 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4928 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4929 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4931 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4932 /* TODO: Move the fbo logic into ModifyLocation() */
4933 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4934 target->Flags |= SFLAG_INTEXTURE;
4942 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4943 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4945 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4947 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4948 Count, pRects, Flags, Color, Z, Stencil);
4950 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4951 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4952 /* TODO: What about depth stencil buffers without stencil bits? */
4953 return WINED3DERR_INVALIDCALL;
4956 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4962 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4963 UINT PrimitiveCount) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4968 debug_d3dprimitivetype(PrimitiveType),
4969 StartVertex, PrimitiveCount);
4971 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4972 if(This->stateBlock->streamIsUP) {
4973 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4974 This->stateBlock->streamIsUP = FALSE;
4977 if(This->stateBlock->loadBaseVertexIndex != 0) {
4978 This->stateBlock->loadBaseVertexIndex = 0;
4979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4981 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4982 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4983 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4987 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4988 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4989 WINED3DPRIMITIVETYPE PrimitiveType,
4990 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4992 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4994 IWineD3DIndexBuffer *pIB;
4995 WINED3DINDEXBUFFER_DESC IdxBufDsc;
4998 pIB = This->stateBlock->pIndexData;
5000 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5001 * without an index buffer set. (The first time at least...)
5002 * D3D8 simply dies, but I doubt it can do much harm to return
5003 * D3DERR_INVALIDCALL there as well. */
5004 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5005 return WINED3DERR_INVALIDCALL;
5008 if(This->stateBlock->streamIsUP) {
5009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5010 This->stateBlock->streamIsUP = FALSE;
5012 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5014 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5015 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5016 minIndex, NumVertices, startIndex, primCount);
5018 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5019 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5025 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5026 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5030 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5031 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5036 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5037 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5038 UINT VertexStreamZeroStride) {
5039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5040 IWineD3DVertexBuffer *vb;
5042 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5043 debug_d3dprimitivetype(PrimitiveType),
5044 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5046 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5047 vb = This->stateBlock->streamSource[0];
5048 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5049 if(vb) IWineD3DVertexBuffer_Release(vb);
5050 This->stateBlock->streamOffset[0] = 0;
5051 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5052 This->stateBlock->streamIsUP = TRUE;
5053 This->stateBlock->loadBaseVertexIndex = 0;
5055 /* TODO: Only mark dirty if drawing from a different UP address */
5056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5058 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5059 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5061 /* MSDN specifies stream zero settings must be set to NULL */
5062 This->stateBlock->streamStride[0] = 0;
5063 This->stateBlock->streamSource[0] = NULL;
5065 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5066 * the new stream sources or use UP drawing again
5071 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5072 UINT MinVertexIndex, UINT NumVertices,
5073 UINT PrimitiveCount, CONST void* pIndexData,
5074 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5075 UINT VertexStreamZeroStride) {
5077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5078 IWineD3DVertexBuffer *vb;
5079 IWineD3DIndexBuffer *ib;
5081 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5082 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5083 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5084 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5086 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5092 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5093 vb = This->stateBlock->streamSource[0];
5094 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5095 if(vb) IWineD3DVertexBuffer_Release(vb);
5096 This->stateBlock->streamIsUP = TRUE;
5097 This->stateBlock->streamOffset[0] = 0;
5098 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5100 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5101 This->stateBlock->baseVertexIndex = 0;
5102 This->stateBlock->loadBaseVertexIndex = 0;
5103 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5107 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5109 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5110 This->stateBlock->streamSource[0] = NULL;
5111 This->stateBlock->streamStride[0] = 0;
5112 ib = This->stateBlock->pIndexData;
5114 IWineD3DIndexBuffer_Release(ib);
5115 This->stateBlock->pIndexData = NULL;
5117 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5118 * SetStreamSource to specify a vertex buffer
5124 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5127 /* Mark the state dirty until we have nicer tracking
5128 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5131 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5133 This->stateBlock->baseVertexIndex = 0;
5134 This->up_strided = DrawPrimStrideData;
5135 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5136 This->up_strided = NULL;
5140 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5142 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5144 /* Mark the state dirty until we have nicer tracking
5145 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5148 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5149 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5150 This->stateBlock->streamIsUP = TRUE;
5151 This->stateBlock->baseVertexIndex = 0;
5152 This->up_strided = DrawPrimStrideData;
5153 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5154 This->up_strided = NULL;
5158 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5159 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5160 * not callable by the app directly no parameter validation checks are needed here.
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5163 WINED3DLOCKED_BOX src;
5164 WINED3DLOCKED_BOX dst;
5166 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5168 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5169 * dirtification to improve loading performance.
5171 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5172 if(FAILED(hr)) return hr;
5173 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5175 IWineD3DVolume_UnlockBox(pSourceVolume);
5179 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5181 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5183 IWineD3DVolume_UnlockBox(pSourceVolume);
5185 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5190 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5191 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5193 HRESULT hr = WINED3D_OK;
5194 WINED3DRESOURCETYPE sourceType;
5195 WINED3DRESOURCETYPE destinationType;
5198 /* TODO: think about moving the code into IWineD3DBaseTexture */
5200 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5202 /* verify that the source and destination textures aren't NULL */
5203 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5204 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5205 This, pSourceTexture, pDestinationTexture);
5206 hr = WINED3DERR_INVALIDCALL;
5209 if (pSourceTexture == pDestinationTexture) {
5210 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5211 This, pSourceTexture, pDestinationTexture);
5212 hr = WINED3DERR_INVALIDCALL;
5214 /* Verify that the source and destination textures are the same type */
5215 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5216 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5218 if (sourceType != destinationType) {
5219 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5221 hr = WINED3DERR_INVALIDCALL;
5224 /* check that both textures have the identical numbers of levels */
5225 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5226 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5227 hr = WINED3DERR_INVALIDCALL;
5230 if (WINED3D_OK == hr) {
5232 /* Make sure that the destination texture is loaded */
5233 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5235 /* Update every surface level of the texture */
5236 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5238 switch (sourceType) {
5239 case WINED3DRTYPE_TEXTURE:
5241 IWineD3DSurface *srcSurface;
5242 IWineD3DSurface *destSurface;
5244 for (i = 0 ; i < levels ; ++i) {
5245 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5246 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5247 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5248 IWineD3DSurface_Release(srcSurface);
5249 IWineD3DSurface_Release(destSurface);
5250 if (WINED3D_OK != hr) {
5251 WARN("(%p) : Call to update surface failed\n", This);
5257 case WINED3DRTYPE_CUBETEXTURE:
5259 IWineD3DSurface *srcSurface;
5260 IWineD3DSurface *destSurface;
5261 WINED3DCUBEMAP_FACES faceType;
5263 for (i = 0 ; i < levels ; ++i) {
5264 /* Update each cube face */
5265 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5266 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5267 if (WINED3D_OK != hr) {
5268 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5270 TRACE("Got srcSurface %p\n", srcSurface);
5272 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5273 if (WINED3D_OK != hr) {
5274 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5276 TRACE("Got desrSurface %p\n", destSurface);
5278 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5279 IWineD3DSurface_Release(srcSurface);
5280 IWineD3DSurface_Release(destSurface);
5281 if (WINED3D_OK != hr) {
5282 WARN("(%p) : Call to update surface failed\n", This);
5290 case WINED3DRTYPE_VOLUMETEXTURE:
5292 IWineD3DVolume *srcVolume = NULL;
5293 IWineD3DVolume *destVolume = NULL;
5295 for (i = 0 ; i < levels ; ++i) {
5296 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5297 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5298 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5299 IWineD3DVolume_Release(srcVolume);
5300 IWineD3DVolume_Release(destVolume);
5301 if (WINED3D_OK != hr) {
5302 WARN("(%p) : Call to update volume failed\n", This);
5310 FIXME("(%p) : Unsupported source and destination type\n", This);
5311 hr = WINED3DERR_INVALIDCALL;
5318 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5319 IWineD3DSwapChain *swapChain;
5321 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5322 if(hr == WINED3D_OK) {
5323 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5324 IWineD3DSwapChain_Release(swapChain);
5329 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5331 /* return a sensible default */
5333 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5334 FIXME("(%p) : stub\n", This);
5338 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5341 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5342 if (PaletteNumber >= MAX_PALETTES) {
5343 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5344 return WINED3DERR_INVALIDCALL;
5346 for (j = 0; j < 256; ++j) {
5347 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5348 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5349 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5350 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5352 TRACE("(%p) : returning\n", This);
5356 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5357 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5359 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5360 if (PaletteNumber >= MAX_PALETTES) {
5361 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5362 return WINED3DERR_INVALIDCALL;
5364 for (j = 0; j < 256; ++j) {
5365 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5366 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5367 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5368 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5370 TRACE("(%p) : returning\n", This);
5374 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5376 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5377 if (PaletteNumber >= MAX_PALETTES) {
5378 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5379 return WINED3DERR_INVALIDCALL;
5381 /*TODO: stateblocks */
5382 This->currentPalette = PaletteNumber;
5383 TRACE("(%p) : returning\n", This);
5387 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5389 if (PaletteNumber == NULL) {
5390 WARN("(%p) : returning Invalid Call\n", This);
5391 return WINED3DERR_INVALIDCALL;
5393 /*TODO: stateblocks */
5394 *PaletteNumber = This->currentPalette;
5395 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5399 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5401 static BOOL showFixmes = TRUE;
5403 FIXME("(%p) : stub\n", This);
5407 This->softwareVertexProcessing = bSoftware;
5412 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5414 static BOOL showFixmes = TRUE;
5416 FIXME("(%p) : stub\n", This);
5419 return This->softwareVertexProcessing;
5423 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5425 IWineD3DSwapChain *swapChain;
5428 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5430 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5431 if(hr == WINED3D_OK){
5432 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5433 IWineD3DSwapChain_Release(swapChain);
5435 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5441 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5443 static BOOL showfixmes = TRUE;
5444 if(nSegments != 0.0f) {
5446 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5453 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 static BOOL showfixmes = TRUE;
5457 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5463 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5465 /** TODO: remove casts to IWineD3DSurfaceImpl
5466 * NOTE: move code to surface to accomplish this
5467 ****************************************/
5468 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5469 int srcWidth, srcHeight;
5470 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5471 WINED3DFORMAT destFormat, srcFormat;
5473 int srcLeft, destLeft, destTop;
5474 WINED3DPOOL srcPool, destPool;
5476 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5477 glDescriptor *glDescription = NULL;
5480 CONVERT_TYPES convert = NO_CONVERSION;
5482 WINED3DSURFACE_DESC winedesc;
5484 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5485 memset(&winedesc, 0, sizeof(winedesc));
5486 winedesc.Width = &srcSurfaceWidth;
5487 winedesc.Height = &srcSurfaceHeight;
5488 winedesc.Pool = &srcPool;
5489 winedesc.Format = &srcFormat;
5491 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5493 winedesc.Width = &destSurfaceWidth;
5494 winedesc.Height = &destSurfaceHeight;
5495 winedesc.Pool = &destPool;
5496 winedesc.Format = &destFormat;
5497 winedesc.Size = &destSize;
5499 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5501 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5502 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5503 return WINED3DERR_INVALIDCALL;
5506 /* This call loads the opengl surface directly, instead of copying the surface to the
5507 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5508 * copy in sysmem and use regular surface loading.
5510 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5511 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5512 if(convert != NO_CONVERSION) {
5513 return IWineD3DSurface_BltFast(pDestinationSurface,
5514 pDestPoint ? pDestPoint->x : 0,
5515 pDestPoint ? pDestPoint->y : 0,
5516 pSourceSurface, (RECT *) pSourceRect, 0);
5519 if (destFormat == WINED3DFMT_UNKNOWN) {
5520 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5521 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5523 /* Get the update surface description */
5524 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5527 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5531 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5532 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5533 checkGLcall("glActiveTextureARB");
5536 /* Make sure the surface is loaded and up to date */
5537 IWineD3DSurface_PreLoad(pDestinationSurface);
5539 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5541 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5542 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5543 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5544 srcLeft = pSourceRect ? pSourceRect->left : 0;
5545 destLeft = pDestPoint ? pDestPoint->x : 0;
5546 destTop = pDestPoint ? pDestPoint->y : 0;
5549 /* This function doesn't support compressed textures
5550 the pitch is just bytesPerPixel * width */
5551 if(srcWidth != srcSurfaceWidth || srcLeft ){
5552 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5553 offset += srcLeft * pSrcSurface->bytesPerPixel;
5554 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5556 /* TODO DXT formats */
5558 if(pSourceRect != NULL && pSourceRect->top != 0){
5559 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5561 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5563 ,glDescription->level
5568 ,glDescription->glFormat
5569 ,glDescription->glType
5570 ,IWineD3DSurface_GetData(pSourceSurface)
5574 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5576 /* need to lock the surface to get the data */
5577 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5580 /* TODO: Cube and volume support */
5582 /* not a whole row so we have to do it a line at a time */
5585 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5586 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5588 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5590 glTexSubImage2D(glDescription->target
5591 ,glDescription->level
5596 ,glDescription->glFormat
5597 ,glDescription->glType
5598 ,data /* could be quicker using */
5603 } else { /* Full width, so just write out the whole texture */
5605 if (WINED3DFMT_DXT1 == destFormat ||
5606 WINED3DFMT_DXT2 == destFormat ||
5607 WINED3DFMT_DXT3 == destFormat ||
5608 WINED3DFMT_DXT4 == destFormat ||
5609 WINED3DFMT_DXT5 == destFormat) {
5610 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5611 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5612 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5613 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5614 } if (destFormat != srcFormat) {
5615 FIXME("Updating mixed format compressed texture is not curretly support\n");
5617 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5618 glDescription->level,
5619 glDescription->glFormatInternal,
5624 IWineD3DSurface_GetData(pSourceSurface));
5627 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5632 glTexSubImage2D(glDescription->target
5633 ,glDescription->level
5638 ,glDescription->glFormat
5639 ,glDescription->glType
5640 ,IWineD3DSurface_GetData(pSourceSurface)
5644 checkGLcall("glTexSubImage2D");
5648 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5654 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5656 struct WineD3DRectPatch *patch;
5660 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5662 if(!(Handle || pRectPatchInfo)) {
5663 /* TODO: Write a test for the return value, thus the FIXME */
5664 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5665 return WINED3DERR_INVALIDCALL;
5669 i = PATCHMAP_HASHFUNC(Handle);
5671 LIST_FOR_EACH(e, &This->patches[i]) {
5672 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5673 if(patch->Handle == Handle) {
5680 TRACE("Patch does not exist. Creating a new one\n");
5681 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5682 patch->Handle = Handle;
5683 list_add_head(&This->patches[i], &patch->entry);
5685 TRACE("Found existing patch %p\n", patch);
5688 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5689 * attributes we have to tesselate, read back, and draw. This needs a patch
5690 * management structure instance. Create one.
5692 * A possible improvement is to check if a vertex shader is used, and if not directly
5695 FIXME("Drawing an uncached patch. This is slow\n");
5696 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5699 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5700 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5701 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5703 TRACE("Tesselation density or patch info changed, retesselating\n");
5705 if(pRectPatchInfo) {
5706 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5708 patch->numSegs[0] = pNumSegs[0];
5709 patch->numSegs[1] = pNumSegs[1];
5710 patch->numSegs[2] = pNumSegs[2];
5711 patch->numSegs[3] = pNumSegs[3];
5713 hr = tesselate_rectpatch(This, patch);
5715 WARN("Patch tesselation failed\n");
5717 /* Do not release the handle to store the params of the patch */
5719 HeapFree(GetProcessHeap(), 0, patch);
5725 This->currentPatch = patch;
5726 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5727 This->currentPatch = NULL;
5729 /* Destroy uncached patches */
5731 HeapFree(GetProcessHeap(), 0, patch->mem);
5732 HeapFree(GetProcessHeap(), 0, patch);
5737 /* http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/reference/d3d/interfaces/idirect3ddevice9/DrawTriPatch.asp */
5738 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5741 FIXME("(%p) : Stub\n", This);
5745 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5748 struct WineD3DRectPatch *patch;
5750 TRACE("(%p) Handle(%d)\n", This, Handle);
5752 i = PATCHMAP_HASHFUNC(Handle);
5753 LIST_FOR_EACH(e, &This->patches[i]) {
5754 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5755 if(patch->Handle == Handle) {
5756 TRACE("Deleting patch %p\n", patch);
5757 list_remove(&patch->entry);
5758 HeapFree(GetProcessHeap(), 0, patch->mem);
5759 HeapFree(GetProcessHeap(), 0, patch);
5764 /* TODO: Write a test for the return value */
5765 FIXME("Attempt to destroy nonexistent patch\n");
5766 return WINED3DERR_INVALIDCALL;
5769 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5771 IWineD3DSwapChain *swapchain;
5773 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5774 if (SUCCEEDED(hr)) {
5775 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5782 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5786 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5787 checkGLcall("glGenFramebuffersEXT()");
5789 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5790 checkGLcall("glBindFramebuffer()");
5793 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5794 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5795 IWineD3DBaseTextureImpl *texture_impl;
5796 GLenum texttarget, target;
5799 texttarget = surface_impl->glDescription.target;
5800 if(texttarget == GL_TEXTURE_2D) {
5801 target = GL_TEXTURE_2D;
5802 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5803 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5804 target = GL_TEXTURE_RECTANGLE_ARB;
5805 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5807 target = GL_TEXTURE_CUBE_MAP_ARB;
5808 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5811 IWineD3DSurface_PreLoad(surface);
5813 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5814 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5815 glBindTexture(target, old_binding);
5817 /* Update base texture states array */
5818 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5819 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5820 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5821 if (texture_impl->baseTexture.bindCount) {
5822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5825 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5828 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5829 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5831 checkGLcall("attach_surface_fbo");
5834 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5835 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5836 IWineD3DSwapChain *swapchain;
5838 swapchain = get_swapchain(surface);
5842 TRACE("Surface %p is onscreen\n", surface);
5844 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5845 buffer = surface_get_gl_buffer(surface, swapchain);
5846 glDrawBuffer(buffer);
5847 checkGLcall("glDrawBuffer()");
5849 TRACE("Surface %p is offscreen\n", surface);
5850 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5851 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5855 glEnable(GL_SCISSOR_TEST);
5857 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5859 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5860 rect->x2 - rect->x1, rect->y2 - rect->y1);
5862 checkGLcall("glScissor");
5864 glDisable(GL_SCISSOR_TEST);
5866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5868 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5869 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5871 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5872 glClear(GL_COLOR_BUFFER_BIT);
5873 checkGLcall("glClear");
5875 if (This->render_offscreen) {
5876 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5878 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5879 checkGLcall("glBindFramebuffer()");
5882 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5883 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5884 glDrawBuffer(GL_BACK);
5885 checkGLcall("glDrawBuffer()");
5889 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5890 unsigned int r, g, b, a;
5893 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5894 destfmt == WINED3DFMT_R8G8B8)
5897 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5899 a = (color & 0xff000000) >> 24;
5900 r = (color & 0x00ff0000) >> 16;
5901 g = (color & 0x0000ff00) >> 8;
5902 b = (color & 0x000000ff) >> 0;
5906 case WINED3DFMT_R5G6B5:
5907 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5914 TRACE("Returning %08x\n", ret);
5917 case WINED3DFMT_X1R5G5B5:
5918 case WINED3DFMT_A1R5G5B5:
5927 TRACE("Returning %08x\n", ret);
5931 TRACE("Returning %08x\n", a);
5934 case WINED3DFMT_X4R4G4B4:
5935 case WINED3DFMT_A4R4G4B4:
5944 TRACE("Returning %08x\n", ret);
5947 case WINED3DFMT_R3G3B2:
5954 TRACE("Returning %08x\n", ret);
5957 case WINED3DFMT_X8B8G8R8:
5958 case WINED3DFMT_A8B8G8R8:
5963 TRACE("Returning %08x\n", ret);
5966 case WINED3DFMT_A2R10G10B10:
5968 r = (r * 1024) / 256;
5969 g = (g * 1024) / 256;
5970 b = (b * 1024) / 256;
5975 TRACE("Returning %08x\n", ret);
5978 case WINED3DFMT_A2B10G10R10:
5980 r = (r * 1024) / 256;
5981 g = (g * 1024) / 256;
5982 b = (b * 1024) / 256;
5987 TRACE("Returning %08x\n", ret);
5991 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
5996 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
5997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5998 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6000 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6002 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6003 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6004 return WINED3DERR_INVALIDCALL;
6007 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6008 color_fill_fbo(iface, pSurface, pRect, color);
6011 /* Just forward this to the DirectDraw blitting engine */
6012 memset(&BltFx, 0, sizeof(BltFx));
6013 BltFx.dwSize = sizeof(BltFx);
6014 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6015 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6019 /* rendertarget and depth stencil functions */
6020 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6021 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6023 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6024 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6025 return WINED3DERR_INVALIDCALL;
6028 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6029 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6030 /* Note inc ref on returned surface */
6031 if(*ppRenderTarget != NULL)
6032 IWineD3DSurface_AddRef(*ppRenderTarget);
6036 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6038 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6039 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6040 IWineD3DSwapChainImpl *Swapchain;
6043 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6045 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6046 if(hr != WINED3D_OK) {
6047 ERR("Can't get the swapchain\n");
6051 /* Make sure to release the swapchain */
6052 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6054 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6055 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6056 return WINED3DERR_INVALIDCALL;
6058 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6059 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6060 return WINED3DERR_INVALIDCALL;
6063 if(Swapchain->frontBuffer != Front) {
6064 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6066 if(Swapchain->frontBuffer)
6067 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6068 Swapchain->frontBuffer = Front;
6070 if(Swapchain->frontBuffer) {
6071 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6075 if(Back && !Swapchain->backBuffer) {
6076 /* We need memory for the back buffer array - only one back buffer this way */
6077 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6078 if(!Swapchain->backBuffer) {
6079 ERR("Out of memory\n");
6080 return E_OUTOFMEMORY;
6084 if(Swapchain->backBuffer[0] != Back) {
6085 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6087 /* What to do about the context here in the case of multithreading? Not sure.
6088 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6091 if(!Swapchain->backBuffer[0]) {
6092 /* GL was told to draw to the front buffer at creation,
6095 glDrawBuffer(GL_BACK);
6096 checkGLcall("glDrawBuffer(GL_BACK)");
6097 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6098 Swapchain->presentParms.BackBufferCount = 1;
6100 /* That makes problems - disable for now */
6101 /* glDrawBuffer(GL_FRONT); */
6102 checkGLcall("glDrawBuffer(GL_FRONT)");
6103 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6104 Swapchain->presentParms.BackBufferCount = 0;
6108 if(Swapchain->backBuffer[0])
6109 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6110 Swapchain->backBuffer[0] = Back;
6112 if(Swapchain->backBuffer[0]) {
6113 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6115 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6116 Swapchain->backBuffer = NULL;
6124 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6125 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6126 *ppZStencilSurface = This->stencilBufferTarget;
6127 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6129 if(*ppZStencilSurface != NULL) {
6130 /* Note inc ref on returned surface */
6131 IWineD3DSurface_AddRef(*ppZStencilSurface);
6134 return WINED3DERR_NOTFOUND;
6138 /* TODO: Handle stencil attachments */
6139 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6140 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6141 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6143 TRACE("Set depth stencil to %p\n", depth_stencil);
6145 if (depth_stencil_impl) {
6146 if (depth_stencil_impl->current_renderbuffer) {
6147 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6148 checkGLcall("glFramebufferRenderbufferEXT()");
6150 IWineD3DBaseTextureImpl *texture_impl;
6151 GLenum texttarget, target;
6152 GLint old_binding = 0;
6154 texttarget = depth_stencil_impl->glDescription.target;
6155 if(texttarget == GL_TEXTURE_2D) {
6156 target = GL_TEXTURE_2D;
6157 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6158 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6159 target = GL_TEXTURE_RECTANGLE_ARB;
6160 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6162 target = GL_TEXTURE_CUBE_MAP_ARB;
6163 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6166 IWineD3DSurface_PreLoad(depth_stencil);
6168 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6169 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6170 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6171 glBindTexture(target, old_binding);
6173 /* Update base texture states array */
6174 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6175 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6176 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6177 if (texture_impl->baseTexture.bindCount) {
6178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6181 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6184 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6185 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6186 checkGLcall("glFramebufferTexture2DEXT()");
6189 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6190 checkGLcall("glFramebufferTexture2DEXT()");
6194 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6196 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6198 TRACE("Set render target %u to %p\n", idx, render_target);
6201 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6202 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6204 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6205 checkGLcall("glFramebufferTexture2DEXT()");
6207 This->draw_buffers[idx] = GL_NONE;
6211 static void check_fbo_status(IWineD3DDevice *iface) {
6212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6215 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6216 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6217 TRACE("FBO complete\n");
6219 IWineD3DSurfaceImpl *attachment;
6221 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6223 /* Dump the FBO attachments */
6224 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6225 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6227 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6228 attachment->pow2Width, attachment->pow2Height);
6231 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6233 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6234 attachment->pow2Width, attachment->pow2Height);
6239 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6240 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6241 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6242 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6244 if (!ds_impl) return FALSE;
6246 if (ds_impl->current_renderbuffer) {
6247 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6248 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6251 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6252 rt_impl->pow2Height != ds_impl->pow2Height);
6255 void apply_fbo_state(IWineD3DDevice *iface) {
6256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6259 if (This->render_offscreen) {
6260 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6262 /* Apply render targets */
6263 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6264 IWineD3DSurface *render_target = This->render_targets[i];
6265 if (This->fbo_color_attachments[i] != render_target) {
6266 set_render_target_fbo(iface, i, render_target);
6267 This->fbo_color_attachments[i] = render_target;
6271 /* Apply depth targets */
6272 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6273 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6274 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6276 if (This->stencilBufferTarget) {
6277 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6279 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6280 This->fbo_depth_attachment = This->stencilBufferTarget;
6283 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6284 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6285 checkGLcall("glDrawBuffers()");
6287 glDrawBuffer(This->draw_buffers[0]);
6288 checkGLcall("glDrawBuffer()");
6291 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6294 check_fbo_status(iface);
6297 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6298 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6300 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6301 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6304 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6305 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6306 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6307 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6310 case WINED3DTEXF_LINEAR:
6311 gl_filter = GL_LINEAR;
6315 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6316 case WINED3DTEXF_NONE:
6317 case WINED3DTEXF_POINT:
6318 gl_filter = GL_NEAREST;
6322 /* Attach src surface to src fbo */
6323 src_swapchain = get_swapchain(src_surface);
6324 if (src_swapchain) {
6327 TRACE("Source surface %p is onscreen\n", src_surface);
6328 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6329 /* Make sure the drawable is up to date. In the offscreen case
6330 * attach_surface_fbo() implicitly takes care of this. */
6331 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6334 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6335 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6336 glReadBuffer(buffer);
6337 checkGLcall("glReadBuffer()");
6339 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6340 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6342 TRACE("Source surface %p is offscreen\n", src_surface);
6344 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6345 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6346 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6347 checkGLcall("glReadBuffer()");
6351 /* Attach dst surface to dst fbo */
6352 dst_swapchain = get_swapchain(dst_surface);
6353 if (dst_swapchain) {
6356 TRACE("Destination surface %p is onscreen\n", dst_surface);
6357 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6358 /* Make sure the drawable is up to date. In the offscreen case
6359 * attach_surface_fbo() implicitly takes care of this. */
6360 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6363 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6364 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6365 glDrawBuffer(buffer);
6366 checkGLcall("glDrawBuffer()");
6368 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6369 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6371 TRACE("Destination surface %p is offscreen\n", dst_surface);
6373 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6374 if(!src_swapchain) {
6375 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6379 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6380 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6381 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6382 checkGLcall("glDrawBuffer()");
6384 glDisable(GL_SCISSOR_TEST);
6385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6388 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6389 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6390 checkGLcall("glBlitFramebuffer()");
6392 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6393 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6394 checkGLcall("glBlitFramebuffer()");
6397 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6399 if (This->render_offscreen) {
6400 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6402 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6403 checkGLcall("glBindFramebuffer()");
6406 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6407 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6408 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6409 glDrawBuffer(GL_BACK);
6410 checkGLcall("glDrawBuffer()");
6415 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6417 WINED3DVIEWPORT viewport;
6419 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6421 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6422 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6423 This, RenderTargetIndex, GL_LIMITS(buffers));
6424 return WINED3DERR_INVALIDCALL;
6427 /* MSDN says that null disables the render target
6428 but a device must always be associated with a render target
6429 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6431 see http://msdn.microsoft.com/library/default.asp?url=/library/en-us/directx9_c/directx/graphics/programmingguide/AdvancedTopics/PixelPipe/MultipleRenderTarget.asp
6434 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6435 FIXME("Trying to set render target 0 to NULL\n");
6436 return WINED3DERR_INVALIDCALL;
6438 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6439 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);
6440 return WINED3DERR_INVALIDCALL;
6443 /* If we are trying to set what we already have, don't bother */
6444 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6445 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6448 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6449 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6450 This->render_targets[RenderTargetIndex] = pRenderTarget;
6452 /* Render target 0 is special */
6453 if(RenderTargetIndex == 0) {
6454 /* Finally, reset the viewport as the MSDN states. */
6455 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6456 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6459 viewport.MaxZ = 1.0f;
6460 viewport.MinZ = 0.0f;
6461 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6462 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6463 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6467 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6469 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6470 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6472 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6477 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6479 HRESULT hr = WINED3D_OK;
6480 IWineD3DSurface *tmp;
6482 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6484 if (pNewZStencil == This->stencilBufferTarget) {
6485 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6487 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6488 * depending on the renter target implementation being used.
6489 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6490 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6491 * stencil buffer and incur an extra memory overhead
6492 ******************************************************/
6494 tmp = This->stencilBufferTarget;
6495 This->stencilBufferTarget = pNewZStencil;
6496 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6497 /* should we be calling the parent or the wined3d surface? */
6498 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6499 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6502 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6503 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6504 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6513 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6514 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6516 /* TODO: the use of Impl is deprecated. */
6517 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6518 WINED3DLOCKED_RECT lockedRect;
6520 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6522 /* some basic validation checks */
6523 if(This->cursorTexture) {
6524 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6526 glDeleteTextures(1, &This->cursorTexture);
6528 This->cursorTexture = 0;
6531 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6532 This->haveHardwareCursor = TRUE;
6534 This->haveHardwareCursor = FALSE;
6537 WINED3DLOCKED_RECT rect;
6539 /* MSDN: Cursor must be A8R8G8B8 */
6540 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6541 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6542 return WINED3DERR_INVALIDCALL;
6545 /* MSDN: Cursor must be smaller than the display mode */
6546 if(pSur->currentDesc.Width > This->ddraw_width ||
6547 pSur->currentDesc.Height > This->ddraw_height) {
6548 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);
6549 return WINED3DERR_INVALIDCALL;
6552 if (!This->haveHardwareCursor) {
6553 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6555 /* Do not store the surface's pointer because the application may
6556 * release it after setting the cursor image. Windows doesn't
6557 * addref the set surface, so we can't do this either without
6558 * creating circular refcount dependencies. Copy out the gl texture
6561 This->cursorWidth = pSur->currentDesc.Width;
6562 This->cursorHeight = pSur->currentDesc.Height;
6563 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6565 const GlPixelFormatDesc *glDesc;
6566 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6567 char *mem, *bits = (char *)rect.pBits;
6568 GLint intfmt = glDesc->glInternal;
6569 GLint format = glDesc->glFormat;
6570 GLint type = glDesc->glType;
6571 INT height = This->cursorHeight;
6572 INT width = This->cursorWidth;
6573 INT bpp = tableEntry->bpp;
6576 /* Reformat the texture memory (pitch and width can be
6578 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6579 for(i = 0; i < height; i++)
6580 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6581 IWineD3DSurface_UnlockRect(pCursorBitmap);
6584 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6585 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6586 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6589 /* Make sure that a proper texture unit is selected */
6590 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6591 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6592 checkGLcall("glActiveTextureARB");
6594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6595 /* Create a new cursor texture */
6596 glGenTextures(1, &This->cursorTexture);
6597 checkGLcall("glGenTextures");
6598 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6599 checkGLcall("glBindTexture");
6600 /* Copy the bitmap memory into the cursor texture */
6601 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6602 HeapFree(GetProcessHeap(), 0, mem);
6603 checkGLcall("glTexImage2D");
6605 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6606 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6607 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6614 FIXME("A cursor texture was not returned.\n");
6615 This->cursorTexture = 0;
6620 /* Draw a hardware cursor */
6621 ICONINFO cursorInfo;
6623 /* Create and clear maskBits because it is not needed for
6624 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6626 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6627 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6628 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6629 WINED3DLOCK_NO_DIRTY_UPDATE |
6630 WINED3DLOCK_READONLY
6632 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6633 pSur->currentDesc.Height);
6635 cursorInfo.fIcon = FALSE;
6636 cursorInfo.xHotspot = XHotSpot;
6637 cursorInfo.yHotspot = YHotSpot;
6638 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6639 pSur->currentDesc.Height, 1,
6641 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6642 pSur->currentDesc.Height, 1,
6643 32, lockedRect.pBits);
6644 IWineD3DSurface_UnlockRect(pCursorBitmap);
6645 /* Create our cursor and clean up. */
6646 cursor = CreateIconIndirect(&cursorInfo);
6648 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6649 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6650 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6651 This->hardwareCursor = cursor;
6652 HeapFree(GetProcessHeap(), 0, maskBits);
6656 This->xHotSpot = XHotSpot;
6657 This->yHotSpot = YHotSpot;
6661 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6663 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6665 This->xScreenSpace = XScreenSpace;
6666 This->yScreenSpace = YScreenSpace;
6672 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6674 BOOL oldVisible = This->bCursorVisible;
6677 TRACE("(%p) : visible(%d)\n", This, bShow);
6680 * When ShowCursor is first called it should make the cursor appear at the OS's last
6681 * known cursor position. Because of this, some applications just repetitively call
6682 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6685 This->xScreenSpace = pt.x;
6686 This->yScreenSpace = pt.y;
6688 if (This->haveHardwareCursor) {
6689 This->bCursorVisible = bShow;
6691 SetCursor(This->hardwareCursor);
6697 if (This->cursorTexture)
6698 This->bCursorVisible = bShow;
6704 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6706 IWineD3DResourceImpl *resource;
6707 TRACE("(%p) : state (%u)\n", This, This->state);
6709 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6710 switch (This->state) {
6713 case WINED3DERR_DEVICELOST:
6715 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6716 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6717 return WINED3DERR_DEVICENOTRESET;
6719 return WINED3DERR_DEVICELOST;
6721 case WINED3DERR_DRIVERINTERNALERROR:
6722 return WINED3DERR_DRIVERINTERNALERROR;
6726 return WINED3DERR_DRIVERINTERNALERROR;
6730 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6732 /** FIXME: Resource tracking needs to be done,
6733 * The closes we can do to this is set the priorities of all managed textures low
6734 * and then reset them.
6735 ***********************************************************/
6736 FIXME("(%p) : stub\n", This);
6740 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6741 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6743 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6744 if(surface->Flags & SFLAG_DIBSECTION) {
6745 /* Release the DC */
6746 SelectObject(surface->hDC, surface->dib.holdbitmap);
6747 DeleteDC(surface->hDC);
6748 /* Release the DIB section */
6749 DeleteObject(surface->dib.DIBsection);
6750 surface->dib.bitmap_data = NULL;
6751 surface->resource.allocatedMemory = NULL;
6752 surface->Flags &= ~SFLAG_DIBSECTION;
6754 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6755 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6756 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6757 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6758 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6760 surface->pow2Width = surface->pow2Height = 1;
6761 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6762 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6764 surface->glRect.left = 0;
6765 surface->glRect.top = 0;
6766 surface->glRect.right = surface->pow2Width;
6767 surface->glRect.bottom = surface->pow2Height;
6769 if(surface->glDescription.textureName) {
6770 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6772 glDeleteTextures(1, &surface->glDescription.textureName);
6774 surface->glDescription.textureName = 0;
6775 surface->Flags &= ~SFLAG_CLIENT;
6777 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6778 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6779 surface->Flags |= SFLAG_NONPOW2;
6781 surface->Flags &= ~SFLAG_NONPOW2;
6783 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6784 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6787 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6788 TRACE("Unloading resource %p\n", resource);
6789 IWineD3DResource_UnLoad(resource);
6790 IWineD3DResource_Release(resource);
6794 static void reset_fbo_state(IWineD3DDevice *iface) {
6795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6799 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6800 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6803 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6806 if (This->src_fbo) {
6807 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6810 if (This->dst_fbo) {
6811 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6814 checkGLcall("Tear down fbos\n");
6817 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6818 This->fbo_color_attachments[i] = NULL;
6820 This->fbo_depth_attachment = NULL;
6823 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6825 WINED3DDISPLAYMODE m;
6828 /* All Windowed modes are supported, as is leaving the current mode */
6829 if(pp->Windowed) return TRUE;
6830 if(!pp->BackBufferWidth) return TRUE;
6831 if(!pp->BackBufferHeight) return TRUE;
6833 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6834 for(i = 0; i < count; i++) {
6835 memset(&m, 0, sizeof(m));
6836 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6838 ERR("EnumAdapterModes failed\n");
6840 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6841 /* Mode found, it is supported */
6845 /* Mode not found -> not supported */
6849 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6851 IWineD3DSwapChainImpl *swapchain;
6853 BOOL DisplayModeChanged = FALSE;
6854 WINED3DDISPLAYMODE mode;
6855 IWineD3DBaseShaderImpl *shader;
6856 IWineD3DSurfaceImpl *target;
6858 TRACE("(%p)\n", This);
6860 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6862 ERR("Failed to get the first implicit swapchain\n");
6866 if(!is_display_mode_supported(This, pPresentationParameters)) {
6867 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6868 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6869 pPresentationParameters->BackBufferHeight);
6870 return WINED3DERR_INVALIDCALL;
6873 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6874 * on an existing gl context, so there's no real need for recreation.
6876 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6878 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6880 TRACE("New params:\n");
6881 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6882 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6883 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6884 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6885 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6886 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6887 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6888 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6889 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6890 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6891 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6892 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6893 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6895 /* No special treatment of these parameters. Just store them */
6896 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6897 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6898 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6899 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6901 /* What to do about these? */
6902 if(pPresentationParameters->BackBufferCount != 0 &&
6903 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6904 ERR("Cannot change the back buffer count yet\n");
6906 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6907 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6908 ERR("Cannot change the back buffer format yet\n");
6910 if(pPresentationParameters->hDeviceWindow != NULL &&
6911 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6912 ERR("Cannot change the device window yet\n");
6914 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6915 ERR("What do do about a changed auto depth stencil parameter?\n");
6918 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6919 reset_fbo_state((IWineD3DDevice *) This);
6922 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6923 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6924 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6928 if(This->depth_blt_texture) {
6929 glDeleteTextures(1, &This->depth_blt_texture);
6930 This->depth_blt_texture = 0;
6932 This->shader_backend->shader_destroy_depth_blt(iface);
6934 for (i = 0; i < GL_LIMITS(textures); i++) {
6935 /* Textures are recreated below */
6936 glDeleteTextures(1, &This->dummyTextureName[i]);
6937 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6938 This->dummyTextureName[i] = 0;
6942 while(This->numContexts) {
6943 DestroyContext(This, This->contexts[0]);
6945 This->activeContext = NULL;
6946 HeapFree(GetProcessHeap(), 0, swapchain->context);
6947 swapchain->context = NULL;
6948 swapchain->num_contexts = 0;
6950 if(pPresentationParameters->Windowed) {
6951 mode.Width = swapchain->orig_width;
6952 mode.Height = swapchain->orig_height;
6953 mode.RefreshRate = 0;
6954 mode.Format = swapchain->presentParms.BackBufferFormat;
6956 mode.Width = pPresentationParameters->BackBufferWidth;
6957 mode.Height = pPresentationParameters->BackBufferHeight;
6958 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6959 mode.Format = swapchain->presentParms.BackBufferFormat;
6962 /* Should Width == 800 && Height == 0 set 800x600? */
6963 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6964 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6965 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6972 vp.Width = pPresentationParameters->BackBufferWidth;
6973 vp.Height = pPresentationParameters->BackBufferHeight;
6977 if(!pPresentationParameters->Windowed) {
6978 DisplayModeChanged = TRUE;
6980 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6981 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6983 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6984 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6985 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6987 if(This->auto_depth_stencil_buffer) {
6988 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6992 /* Now set the new viewport */
6993 IWineD3DDevice_SetViewport(iface, &vp);
6996 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6997 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6998 DisplayModeChanged) {
7000 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
7001 if(!pPresentationParameters->Windowed) {
7002 IWineD3DDevice_SetFullscreen(iface, TRUE);
7005 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7007 /* Switching out of fullscreen mode? First set the original res, then change the window */
7008 if(pPresentationParameters->Windowed) {
7009 IWineD3DDevice_SetFullscreen(iface, FALSE);
7011 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7012 } else if(!pPresentationParameters->Windowed) {
7013 DWORD style = This->style, exStyle = This->exStyle;
7014 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7015 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7016 * Reset to clear up their mess. Guild Wars also loses the device during that.
7020 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7021 This->style = style;
7022 This->exStyle = exStyle;
7025 /* Recreate the primary swapchain's context */
7026 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7027 if(swapchain->backBuffer) {
7028 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7030 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7032 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7033 &swapchain->presentParms);
7034 swapchain->num_contexts = 1;
7035 This->activeContext = swapchain->context[0];
7037 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7039 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7041 create_dummy_textures(This);
7043 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7047 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7051 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7053 /** FIXME: always true at the moment **/
7054 if(!bEnableDialogs) {
7055 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7061 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7063 TRACE("(%p) : pParameters %p\n", This, pParameters);
7065 *pParameters = This->createParms;
7069 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7070 IWineD3DSwapChain *swapchain;
7071 HRESULT hrc = WINED3D_OK;
7073 TRACE("Relaying to swapchain\n");
7075 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7076 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7077 IWineD3DSwapChain_Release(swapchain);
7082 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7083 IWineD3DSwapChain *swapchain;
7084 HRESULT hrc = WINED3D_OK;
7086 TRACE("Relaying to swapchain\n");
7088 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7089 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7090 IWineD3DSwapChain_Release(swapchain);
7096 /** ********************************************************
7097 * Notification functions
7098 ** ********************************************************/
7099 /** This function must be called in the release of a resource when ref == 0,
7100 * the contents of resource must still be correct,
7101 * any handles to other resource held by the caller must be closed
7102 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7103 *****************************************************/
7104 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7107 TRACE("(%p) : Adding Resource %p\n", This, resource);
7108 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7111 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7114 TRACE("(%p) : Removing resource %p\n", This, resource);
7116 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7120 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7124 TRACE("(%p) : resource %p\n", This, resource);
7125 switch(IWineD3DResource_GetType(resource)){
7126 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7127 case WINED3DRTYPE_SURFACE: {
7130 /* Cleanup any FBO attachments if d3d is enabled */
7131 if(This->d3d_initialized) {
7132 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7133 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7135 TRACE("Last active render target destroyed\n");
7136 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7137 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7138 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7139 * and the lastActiveRenderTarget member shouldn't matter
7142 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7143 TRACE("Activating primary back buffer\n");
7144 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7145 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7146 /* Single buffering environment */
7147 TRACE("Activating primary front buffer\n");
7148 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7150 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7151 /* Implicit render target destroyed, that means the device is being destroyed
7152 * whatever we set here, it shouldn't matter
7154 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7157 /* May happen during ddraw uninitialization */
7158 TRACE("Render target set, but swapchain does not exist!\n");
7159 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7163 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7164 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7165 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7166 set_render_target_fbo(iface, i, NULL);
7167 This->fbo_color_attachments[i] = NULL;
7170 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7171 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7172 set_depth_stencil_fbo(iface, NULL);
7173 This->fbo_depth_attachment = NULL;
7179 case WINED3DRTYPE_TEXTURE:
7180 case WINED3DRTYPE_CUBETEXTURE:
7181 case WINED3DRTYPE_VOLUMETEXTURE:
7182 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7183 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7184 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7185 This->stateBlock->textures[counter] = NULL;
7187 if (This->updateStateBlock != This->stateBlock ){
7188 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7189 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7190 This->updateStateBlock->textures[counter] = NULL;
7195 case WINED3DRTYPE_VOLUME:
7196 /* TODO: nothing really? */
7198 case WINED3DRTYPE_VERTEXBUFFER:
7199 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7202 TRACE("Cleaning up stream pointers\n");
7204 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7205 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7206 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7208 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7209 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7210 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7211 This->updateStateBlock->streamSource[streamNumber] = 0;
7212 /* Set changed flag? */
7215 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) */
7216 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7217 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7218 This->stateBlock->streamSource[streamNumber] = 0;
7221 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7222 else { /* This shouldn't happen */
7223 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7230 case WINED3DRTYPE_INDEXBUFFER:
7231 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7232 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7233 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7234 This->updateStateBlock->pIndexData = NULL;
7237 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7238 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7239 This->stateBlock->pIndexData = NULL;
7245 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7250 /* Remove the resource from the resourceStore */
7251 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7253 TRACE("Resource released\n");
7257 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7259 IWineD3DResourceImpl *resource, *cursor;
7261 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7263 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7264 TRACE("enumerating resource %p\n", resource);
7265 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7266 ret = pCallback((IWineD3DResource *) resource, pData);
7267 if(ret == S_FALSE) {
7268 TRACE("Canceling enumeration\n");
7275 /**********************************************************
7276 * IWineD3DDevice VTbl follows
7277 **********************************************************/
7279 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7281 /*** IUnknown methods ***/
7282 IWineD3DDeviceImpl_QueryInterface,
7283 IWineD3DDeviceImpl_AddRef,
7284 IWineD3DDeviceImpl_Release,
7285 /*** IWineD3DDevice methods ***/
7286 IWineD3DDeviceImpl_GetParent,
7287 /*** Creation methods**/
7288 IWineD3DDeviceImpl_CreateVertexBuffer,
7289 IWineD3DDeviceImpl_CreateIndexBuffer,
7290 IWineD3DDeviceImpl_CreateStateBlock,
7291 IWineD3DDeviceImpl_CreateSurface,
7292 IWineD3DDeviceImpl_CreateTexture,
7293 IWineD3DDeviceImpl_CreateVolumeTexture,
7294 IWineD3DDeviceImpl_CreateVolume,
7295 IWineD3DDeviceImpl_CreateCubeTexture,
7296 IWineD3DDeviceImpl_CreateQuery,
7297 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7298 IWineD3DDeviceImpl_CreateVertexDeclaration,
7299 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7300 IWineD3DDeviceImpl_CreateVertexShader,
7301 IWineD3DDeviceImpl_CreatePixelShader,
7302 IWineD3DDeviceImpl_CreatePalette,
7303 /*** Odd functions **/
7304 IWineD3DDeviceImpl_Init3D,
7305 IWineD3DDeviceImpl_Uninit3D,
7306 IWineD3DDeviceImpl_SetFullscreen,
7307 IWineD3DDeviceImpl_SetMultithreaded,
7308 IWineD3DDeviceImpl_EvictManagedResources,
7309 IWineD3DDeviceImpl_GetAvailableTextureMem,
7310 IWineD3DDeviceImpl_GetBackBuffer,
7311 IWineD3DDeviceImpl_GetCreationParameters,
7312 IWineD3DDeviceImpl_GetDeviceCaps,
7313 IWineD3DDeviceImpl_GetDirect3D,
7314 IWineD3DDeviceImpl_GetDisplayMode,
7315 IWineD3DDeviceImpl_SetDisplayMode,
7316 IWineD3DDeviceImpl_GetHWND,
7317 IWineD3DDeviceImpl_SetHWND,
7318 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7319 IWineD3DDeviceImpl_GetRasterStatus,
7320 IWineD3DDeviceImpl_GetSwapChain,
7321 IWineD3DDeviceImpl_Reset,
7322 IWineD3DDeviceImpl_SetDialogBoxMode,
7323 IWineD3DDeviceImpl_SetCursorProperties,
7324 IWineD3DDeviceImpl_SetCursorPosition,
7325 IWineD3DDeviceImpl_ShowCursor,
7326 IWineD3DDeviceImpl_TestCooperativeLevel,
7327 /*** Getters and setters **/
7328 IWineD3DDeviceImpl_SetClipPlane,
7329 IWineD3DDeviceImpl_GetClipPlane,
7330 IWineD3DDeviceImpl_SetClipStatus,
7331 IWineD3DDeviceImpl_GetClipStatus,
7332 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7333 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7334 IWineD3DDeviceImpl_SetDepthStencilSurface,
7335 IWineD3DDeviceImpl_GetDepthStencilSurface,
7336 IWineD3DDeviceImpl_SetFVF,
7337 IWineD3DDeviceImpl_GetFVF,
7338 IWineD3DDeviceImpl_SetGammaRamp,
7339 IWineD3DDeviceImpl_GetGammaRamp,
7340 IWineD3DDeviceImpl_SetIndices,
7341 IWineD3DDeviceImpl_GetIndices,
7342 IWineD3DDeviceImpl_SetBaseVertexIndex,
7343 IWineD3DDeviceImpl_GetBaseVertexIndex,
7344 IWineD3DDeviceImpl_SetLight,
7345 IWineD3DDeviceImpl_GetLight,
7346 IWineD3DDeviceImpl_SetLightEnable,
7347 IWineD3DDeviceImpl_GetLightEnable,
7348 IWineD3DDeviceImpl_SetMaterial,
7349 IWineD3DDeviceImpl_GetMaterial,
7350 IWineD3DDeviceImpl_SetNPatchMode,
7351 IWineD3DDeviceImpl_GetNPatchMode,
7352 IWineD3DDeviceImpl_SetPaletteEntries,
7353 IWineD3DDeviceImpl_GetPaletteEntries,
7354 IWineD3DDeviceImpl_SetPixelShader,
7355 IWineD3DDeviceImpl_GetPixelShader,
7356 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7357 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7358 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7359 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7360 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7361 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7362 IWineD3DDeviceImpl_SetRenderState,
7363 IWineD3DDeviceImpl_GetRenderState,
7364 IWineD3DDeviceImpl_SetRenderTarget,
7365 IWineD3DDeviceImpl_GetRenderTarget,
7366 IWineD3DDeviceImpl_SetFrontBackBuffers,
7367 IWineD3DDeviceImpl_SetSamplerState,
7368 IWineD3DDeviceImpl_GetSamplerState,
7369 IWineD3DDeviceImpl_SetScissorRect,
7370 IWineD3DDeviceImpl_GetScissorRect,
7371 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7372 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7373 IWineD3DDeviceImpl_SetStreamSource,
7374 IWineD3DDeviceImpl_GetStreamSource,
7375 IWineD3DDeviceImpl_SetStreamSourceFreq,
7376 IWineD3DDeviceImpl_GetStreamSourceFreq,
7377 IWineD3DDeviceImpl_SetTexture,
7378 IWineD3DDeviceImpl_GetTexture,
7379 IWineD3DDeviceImpl_SetTextureStageState,
7380 IWineD3DDeviceImpl_GetTextureStageState,
7381 IWineD3DDeviceImpl_SetTransform,
7382 IWineD3DDeviceImpl_GetTransform,
7383 IWineD3DDeviceImpl_SetVertexDeclaration,
7384 IWineD3DDeviceImpl_GetVertexDeclaration,
7385 IWineD3DDeviceImpl_SetVertexShader,
7386 IWineD3DDeviceImpl_GetVertexShader,
7387 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7388 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7389 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7390 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7391 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7392 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7393 IWineD3DDeviceImpl_SetViewport,
7394 IWineD3DDeviceImpl_GetViewport,
7395 IWineD3DDeviceImpl_MultiplyTransform,
7396 IWineD3DDeviceImpl_ValidateDevice,
7397 IWineD3DDeviceImpl_ProcessVertices,
7398 /*** State block ***/
7399 IWineD3DDeviceImpl_BeginStateBlock,
7400 IWineD3DDeviceImpl_EndStateBlock,
7401 /*** Scene management ***/
7402 IWineD3DDeviceImpl_BeginScene,
7403 IWineD3DDeviceImpl_EndScene,
7404 IWineD3DDeviceImpl_Present,
7405 IWineD3DDeviceImpl_Clear,
7407 IWineD3DDeviceImpl_DrawPrimitive,
7408 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7409 IWineD3DDeviceImpl_DrawPrimitiveUP,
7410 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7411 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7412 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7413 IWineD3DDeviceImpl_DrawRectPatch,
7414 IWineD3DDeviceImpl_DrawTriPatch,
7415 IWineD3DDeviceImpl_DeletePatch,
7416 IWineD3DDeviceImpl_ColorFill,
7417 IWineD3DDeviceImpl_UpdateTexture,
7418 IWineD3DDeviceImpl_UpdateSurface,
7419 IWineD3DDeviceImpl_GetFrontBufferData,
7420 /*** object tracking ***/
7421 IWineD3DDeviceImpl_ResourceReleased,
7422 IWineD3DDeviceImpl_EnumResources
7426 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7427 WINED3DRS_ALPHABLENDENABLE ,
7428 WINED3DRS_ALPHAFUNC ,
7429 WINED3DRS_ALPHAREF ,
7430 WINED3DRS_ALPHATESTENABLE ,
7432 WINED3DRS_COLORWRITEENABLE ,
7433 WINED3DRS_DESTBLEND ,
7434 WINED3DRS_DITHERENABLE ,
7435 WINED3DRS_FILLMODE ,
7436 WINED3DRS_FOGDENSITY ,
7438 WINED3DRS_FOGSTART ,
7439 WINED3DRS_LASTPIXEL ,
7440 WINED3DRS_SHADEMODE ,
7441 WINED3DRS_SRCBLEND ,
7442 WINED3DRS_STENCILENABLE ,
7443 WINED3DRS_STENCILFAIL ,
7444 WINED3DRS_STENCILFUNC ,
7445 WINED3DRS_STENCILMASK ,
7446 WINED3DRS_STENCILPASS ,
7447 WINED3DRS_STENCILREF ,
7448 WINED3DRS_STENCILWRITEMASK ,
7449 WINED3DRS_STENCILZFAIL ,
7450 WINED3DRS_TEXTUREFACTOR ,
7461 WINED3DRS_ZWRITEENABLE
7464 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7465 WINED3DTSS_ADDRESSW ,
7466 WINED3DTSS_ALPHAARG0 ,
7467 WINED3DTSS_ALPHAARG1 ,
7468 WINED3DTSS_ALPHAARG2 ,
7469 WINED3DTSS_ALPHAOP ,
7470 WINED3DTSS_BUMPENVLOFFSET ,
7471 WINED3DTSS_BUMPENVLSCALE ,
7472 WINED3DTSS_BUMPENVMAT00 ,
7473 WINED3DTSS_BUMPENVMAT01 ,
7474 WINED3DTSS_BUMPENVMAT10 ,
7475 WINED3DTSS_BUMPENVMAT11 ,
7476 WINED3DTSS_COLORARG0 ,
7477 WINED3DTSS_COLORARG1 ,
7478 WINED3DTSS_COLORARG2 ,
7479 WINED3DTSS_COLOROP ,
7480 WINED3DTSS_RESULTARG ,
7481 WINED3DTSS_TEXCOORDINDEX ,
7482 WINED3DTSS_TEXTURETRANSFORMFLAGS
7485 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7486 WINED3DSAMP_ADDRESSU ,
7487 WINED3DSAMP_ADDRESSV ,
7488 WINED3DSAMP_ADDRESSW ,
7489 WINED3DSAMP_BORDERCOLOR ,
7490 WINED3DSAMP_MAGFILTER ,
7491 WINED3DSAMP_MINFILTER ,
7492 WINED3DSAMP_MIPFILTER ,
7493 WINED3DSAMP_MIPMAPLODBIAS ,
7494 WINED3DSAMP_MAXMIPLEVEL ,
7495 WINED3DSAMP_MAXANISOTROPY ,
7496 WINED3DSAMP_SRGBTEXTURE ,
7497 WINED3DSAMP_ELEMENTINDEX
7500 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7502 WINED3DRS_AMBIENTMATERIALSOURCE ,
7503 WINED3DRS_CLIPPING ,
7504 WINED3DRS_CLIPPLANEENABLE ,
7505 WINED3DRS_COLORVERTEX ,
7506 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7507 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7508 WINED3DRS_FOGDENSITY ,
7510 WINED3DRS_FOGSTART ,
7511 WINED3DRS_FOGTABLEMODE ,
7512 WINED3DRS_FOGVERTEXMODE ,
7513 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7514 WINED3DRS_LIGHTING ,
7515 WINED3DRS_LOCALVIEWER ,
7516 WINED3DRS_MULTISAMPLEANTIALIAS ,
7517 WINED3DRS_MULTISAMPLEMASK ,
7518 WINED3DRS_NORMALIZENORMALS ,
7519 WINED3DRS_PATCHEDGESTYLE ,
7520 WINED3DRS_POINTSCALE_A ,
7521 WINED3DRS_POINTSCALE_B ,
7522 WINED3DRS_POINTSCALE_C ,
7523 WINED3DRS_POINTSCALEENABLE ,
7524 WINED3DRS_POINTSIZE ,
7525 WINED3DRS_POINTSIZE_MAX ,
7526 WINED3DRS_POINTSIZE_MIN ,
7527 WINED3DRS_POINTSPRITEENABLE ,
7528 WINED3DRS_RANGEFOGENABLE ,
7529 WINED3DRS_SPECULARMATERIALSOURCE ,
7530 WINED3DRS_TWEENFACTOR ,
7531 WINED3DRS_VERTEXBLEND ,
7532 WINED3DRS_CULLMODE ,
7536 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7537 WINED3DTSS_TEXCOORDINDEX ,
7538 WINED3DTSS_TEXTURETRANSFORMFLAGS
7541 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7542 WINED3DSAMP_DMAPOFFSET
7545 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7546 DWORD rep = StateTable[state].representative;
7550 WineD3DContext *context;
7553 for(i = 0; i < This->numContexts; i++) {
7554 context = This->contexts[i];
7555 if(isStateDirty(context, rep)) continue;
7557 context->dirtyArray[context->numDirtyEntries++] = rep;
7560 context->isStateDirty[idx] |= (1 << shift);
7564 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7565 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7566 /* The drawable size of a pbuffer render target is the current pbuffer size
7568 *width = dev->pbufferWidth;
7569 *height = dev->pbufferHeight;
7572 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7573 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7575 *width = This->pow2Width;
7576 *height = This->pow2Height;
7579 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7580 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7581 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7582 * current context's drawable, which is the size of the back buffer of the swapchain
7583 * the active context belongs to. The back buffer of the swapchain is stored as the
7584 * surface the context belongs to.
7586 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7587 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;