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;
1146 const IWineD3DQueryVtbl *vtable;
1148 /* Just a check to see if we support this type of query */
1150 case WINED3DQUERYTYPE_OCCLUSION:
1151 TRACE("(%p) occlusion query\n", This);
1152 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1155 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1157 vtable = &IWineD3DOcclusionQuery_Vtbl;
1160 case WINED3DQUERYTYPE_EVENT:
1161 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1162 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1163 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1165 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1167 vtable = &IWineD3DEventQuery_Vtbl;
1171 case WINED3DQUERYTYPE_VCACHE:
1172 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1173 case WINED3DQUERYTYPE_VERTEXSTATS:
1174 case WINED3DQUERYTYPE_TIMESTAMP:
1175 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1176 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1177 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1178 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1179 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1180 case WINED3DQUERYTYPE_PIXELTIMINGS:
1181 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1182 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1184 /* Use the base Query vtable until we have a special one for each query */
1185 vtable = &IWineD3DQuery_Vtbl;
1186 FIXME("(%p) Unhandled query type %d\n", This, Type);
1188 if(NULL == ppQuery || hr != WINED3D_OK) {
1192 D3DCREATEOBJECTINSTANCE(object, Query)
1193 object->lpVtbl = vtable;
1194 object->type = Type;
1195 object->state = QUERY_CREATED;
1196 /* allocated the 'extended' data based on the type of query requested */
1198 case WINED3DQUERYTYPE_OCCLUSION:
1199 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1200 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1202 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1203 TRACE("(%p) Allocating data for an occlusion query\n", This);
1204 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1207 case WINED3DQUERYTYPE_EVENT:
1208 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1209 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1211 if(GL_SUPPORT(APPLE_FENCE)) {
1212 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1213 checkGLcall("glGenFencesAPPLE");
1214 } else if(GL_SUPPORT(NV_FENCE)) {
1215 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1216 checkGLcall("glGenFencesNV");
1220 case WINED3DQUERYTYPE_VCACHE:
1221 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1222 case WINED3DQUERYTYPE_VERTEXSTATS:
1223 case WINED3DQUERYTYPE_TIMESTAMP:
1224 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1225 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1226 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1227 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1228 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1229 case WINED3DQUERYTYPE_PIXELTIMINGS:
1230 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1231 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1233 object->extendedData = 0;
1234 FIXME("(%p) Unhandled query type %d\n",This , Type);
1236 TRACE("(%p) : Created Query %p\n", This, object);
1240 /*****************************************************************************
1241 * IWineD3DDeviceImpl_SetupFullscreenWindow
1243 * Helper function that modifies a HWND's Style and ExStyle for proper
1247 * iface: Pointer to the IWineD3DDevice interface
1248 * window: Window to setup
1250 *****************************************************************************/
1251 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1254 LONG style, exStyle;
1255 /* Don't do anything if an original style is stored.
1256 * That shouldn't happen
1258 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1259 if (This->style || This->exStyle) {
1260 ERR("(%p): Want to change the window parameters of HWND %p, but "
1261 "another style is stored for restoration afterwards\n", This, window);
1264 /* Get the parameters and save them */
1265 style = GetWindowLongW(window, GWL_STYLE);
1266 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1267 This->style = style;
1268 This->exStyle = exStyle;
1270 /* Filter out window decorations */
1271 style &= ~WS_CAPTION;
1272 style &= ~WS_THICKFRAME;
1273 exStyle &= ~WS_EX_WINDOWEDGE;
1274 exStyle &= ~WS_EX_CLIENTEDGE;
1276 /* Make sure the window is managed, otherwise we won't get keyboard input */
1277 style |= WS_POPUP | WS_SYSMENU;
1279 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1280 This->style, This->exStyle, style, exStyle);
1282 SetWindowLongW(window, GWL_STYLE, style);
1283 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1285 /* Inform the window about the update. */
1286 SetWindowPos(window, HWND_TOP, 0, 0,
1287 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1288 ShowWindow(window, SW_NORMAL);
1291 /*****************************************************************************
1292 * IWineD3DDeviceImpl_RestoreWindow
1294 * Helper function that restores a windows' properties when taking it out
1295 * of fullscreen mode
1298 * iface: Pointer to the IWineD3DDevice interface
1299 * window: Window to setup
1301 *****************************************************************************/
1302 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1306 * switch, do nothing
1308 if (!This->style && !This->exStyle) return;
1310 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1311 This, window, This->style, This->exStyle);
1313 SetWindowLongW(window, GWL_STYLE, This->style);
1314 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1316 /* Delete the old values */
1320 /* Inform the window about the update */
1321 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1322 0, 0, 0, 0, /* Pos, Size, ignored */
1323 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1326 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1327 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1329 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1330 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1334 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1335 HRESULT hr = WINED3D_OK;
1336 IUnknown *bufferParent;
1337 BOOL displaymode_set = FALSE;
1338 WINED3DDISPLAYMODE Mode;
1339 const StaticPixelFormatDesc *formatDesc;
1341 TRACE("(%p) : Created Additional Swap Chain\n", This);
1343 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1344 * does a device hold a reference to a swap chain giving them a lifetime of the device
1345 * or does the swap chain notify the device of its destruction.
1346 *******************************/
1348 /* Check the params */
1349 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1350 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1351 return WINED3DERR_INVALIDCALL;
1352 } else if (pPresentationParameters->BackBufferCount > 1) {
1353 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");
1356 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1358 /*********************
1359 * Lookup the window Handle and the relating X window handle
1360 ********************/
1362 /* Setup hwnd we are using, plus which display this equates to */
1363 object->win_handle = pPresentationParameters->hDeviceWindow;
1364 if (!object->win_handle) {
1365 object->win_handle = This->createParms.hFocusWindow;
1367 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1369 hDc = GetDC(object->win_handle);
1370 TRACE("Using hDc %p\n", hDc);
1373 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1374 return WINED3DERR_NOTAVAILABLE;
1377 /* Get info on the current display setup */
1378 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1379 object->orig_width = Mode.Width;
1380 object->orig_height = Mode.Height;
1381 object->orig_fmt = Mode.Format;
1382 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1384 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1385 * then the corresponding dimension of the client area of the hDeviceWindow
1386 * (or the focus window, if hDeviceWindow is NULL) is taken.
1387 **********************/
1389 if (pPresentationParameters->Windowed &&
1390 ((pPresentationParameters->BackBufferWidth == 0) ||
1391 (pPresentationParameters->BackBufferHeight == 0) ||
1392 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1395 GetClientRect(object->win_handle, &Rect);
1397 if (pPresentationParameters->BackBufferWidth == 0) {
1398 pPresentationParameters->BackBufferWidth = Rect.right;
1399 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1401 if (pPresentationParameters->BackBufferHeight == 0) {
1402 pPresentationParameters->BackBufferHeight = Rect.bottom;
1403 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1405 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1406 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1407 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1411 /* Put the correct figures in the presentation parameters */
1412 TRACE("Copying across presentation parameters\n");
1413 object->presentParms = *pPresentationParameters;
1415 TRACE("calling rendertarget CB\n");
1416 hr = D3DCB_CreateRenderTarget(This->parent,
1418 object->presentParms.BackBufferWidth,
1419 object->presentParms.BackBufferHeight,
1420 object->presentParms.BackBufferFormat,
1421 object->presentParms.MultiSampleType,
1422 object->presentParms.MultiSampleQuality,
1423 TRUE /* Lockable */,
1424 &object->frontBuffer,
1425 NULL /* pShared (always null)*/);
1426 if (object->frontBuffer != NULL) {
1427 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1428 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1430 ERR("Failed to create the front buffer\n");
1434 /*********************
1435 * Windowed / Fullscreen
1436 *******************/
1439 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1440 * so we should really check to see if there is a fullscreen swapchain already
1441 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1442 **************************************/
1444 if (!pPresentationParameters->Windowed) {
1445 WINED3DDISPLAYMODE mode;
1448 /* Change the display settings */
1449 mode.Width = pPresentationParameters->BackBufferWidth;
1450 mode.Height = pPresentationParameters->BackBufferHeight;
1451 mode.Format = pPresentationParameters->BackBufferFormat;
1452 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1454 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1455 displaymode_set = TRUE;
1456 IWineD3DDevice_SetFullscreen(iface, TRUE);
1460 * Create an opengl context for the display visual
1461 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1462 * use different properties after that point in time. FIXME: How to handle when requested format
1463 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1464 * it chooses is identical to the one already being used!
1465 **********************************/
1466 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1468 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1469 if(!object->context)
1470 return E_OUTOFMEMORY;
1471 object->num_contexts = 1;
1473 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1474 if (!object->context[0]) {
1475 ERR("Failed to create a new context\n");
1476 hr = WINED3DERR_NOTAVAILABLE;
1479 TRACE("Context created (HWND=%p, glContext=%p)\n",
1480 object->win_handle, object->context[0]->glCtx);
1483 /*********************
1484 * Create the back, front and stencil buffers
1485 *******************/
1486 if(object->presentParms.BackBufferCount > 0) {
1489 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1490 if(!object->backBuffer) {
1491 ERR("Out of memory\n");
1496 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1497 TRACE("calling rendertarget CB\n");
1498 hr = D3DCB_CreateRenderTarget(This->parent,
1500 object->presentParms.BackBufferWidth,
1501 object->presentParms.BackBufferHeight,
1502 object->presentParms.BackBufferFormat,
1503 object->presentParms.MultiSampleType,
1504 object->presentParms.MultiSampleQuality,
1505 TRUE /* Lockable */,
1506 &object->backBuffer[i],
1507 NULL /* pShared (always null)*/);
1508 if(hr == WINED3D_OK && object->backBuffer[i]) {
1509 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1511 ERR("Cannot create new back buffer\n");
1515 glDrawBuffer(GL_BACK);
1516 checkGLcall("glDrawBuffer(GL_BACK)");
1520 object->backBuffer = NULL;
1522 /* Single buffering - draw to front buffer */
1524 glDrawBuffer(GL_FRONT);
1525 checkGLcall("glDrawBuffer(GL_FRONT)");
1529 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1530 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1531 TRACE("Creating depth stencil buffer\n");
1532 if (This->auto_depth_stencil_buffer == NULL ) {
1533 hr = D3DCB_CreateDepthStencil(This->parent,
1535 object->presentParms.BackBufferWidth,
1536 object->presentParms.BackBufferHeight,
1537 object->presentParms.AutoDepthStencilFormat,
1538 object->presentParms.MultiSampleType,
1539 object->presentParms.MultiSampleQuality,
1540 FALSE /* FIXME: Discard */,
1541 &This->auto_depth_stencil_buffer,
1542 NULL /* pShared (always null)*/ );
1543 if (This->auto_depth_stencil_buffer != NULL)
1544 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1547 /** TODO: A check on width, height and multisample types
1548 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1549 ****************************/
1550 object->wantsDepthStencilBuffer = TRUE;
1552 object->wantsDepthStencilBuffer = FALSE;
1555 TRACE("Created swapchain %p\n", object);
1556 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1560 if (displaymode_set) {
1564 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1567 /* Change the display settings */
1568 memset(&devmode, 0, sizeof(devmode));
1569 devmode.dmSize = sizeof(devmode);
1570 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1571 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1572 devmode.dmPelsWidth = object->orig_width;
1573 devmode.dmPelsHeight = object->orig_height;
1574 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1577 if (object->backBuffer) {
1579 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1580 if(object->backBuffer[i]) {
1581 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1582 IUnknown_Release(bufferParent); /* once for the get parent */
1583 if (IUnknown_Release(bufferParent) > 0) {
1584 FIXME("(%p) Something's still holding the back buffer\n",This);
1588 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1589 object->backBuffer = NULL;
1591 if(object->context[0])
1592 DestroyContext(This, object->context[0]);
1593 if(object->frontBuffer) {
1594 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1595 IUnknown_Release(bufferParent); /* once for the get parent */
1596 if (IUnknown_Release(bufferParent) > 0) {
1597 FIXME("(%p) Something's still holding the front buffer\n",This);
1600 HeapFree(GetProcessHeap(), 0, object);
1604 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1605 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1607 TRACE("(%p)\n", This);
1609 return This->NumberOfSwapChains;
1612 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1614 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1616 if(iSwapChain < This->NumberOfSwapChains) {
1617 *pSwapChain = This->swapchains[iSwapChain];
1618 IWineD3DSwapChain_AddRef(*pSwapChain);
1619 TRACE("(%p) returning %p\n", This, *pSwapChain);
1622 TRACE("Swapchain out of range\n");
1624 return WINED3DERR_INVALIDCALL;
1629 * Vertex Declaration
1631 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1632 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1633 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1634 IWineD3DVertexDeclarationImpl *object = NULL;
1635 HRESULT hr = WINED3D_OK;
1637 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1638 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1640 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1642 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1644 *ppVertexDeclaration = NULL;
1645 HeapFree(GetProcessHeap(), 0, object);
1651 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1652 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1654 unsigned int idx, idx2;
1655 unsigned int offset;
1656 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1657 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1658 BOOL has_blend_idx = has_blend &&
1659 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1660 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1661 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1662 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1663 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1664 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1665 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1667 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1668 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1670 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1671 WINED3DVERTEXELEMENT *elements = NULL;
1674 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1675 if (has_blend_idx) num_blends--;
1677 /* Compute declaration size */
1678 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1679 has_psize + has_diffuse + has_specular + num_textures + 1;
1681 /* convert the declaration */
1682 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1686 memcpy(&elements[size-1], &end_element, sizeof(WINED3DVERTEXELEMENT));
1689 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1690 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1691 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1694 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1695 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1697 elements[idx].UsageIndex = 0;
1700 if (has_blend && (num_blends > 0)) {
1701 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1702 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1704 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1705 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1706 elements[idx].UsageIndex = 0;
1709 if (has_blend_idx) {
1710 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1711 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1712 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1713 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1714 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1716 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1717 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1718 elements[idx].UsageIndex = 0;
1722 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1723 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1724 elements[idx].UsageIndex = 0;
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1729 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1730 elements[idx].UsageIndex = 0;
1734 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1735 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1736 elements[idx].UsageIndex = 0;
1740 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1741 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1742 elements[idx].UsageIndex = 1;
1745 for (idx2 = 0; idx2 < num_textures; idx2++) {
1746 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1747 switch (numcoords) {
1748 case WINED3DFVF_TEXTUREFORMAT1:
1749 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1751 case WINED3DFVF_TEXTUREFORMAT2:
1752 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1754 case WINED3DFVF_TEXTUREFORMAT3:
1755 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1757 case WINED3DFVF_TEXTUREFORMAT4:
1758 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1761 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1762 elements[idx].UsageIndex = idx2;
1766 /* Now compute offsets, and initialize the rest of the fields */
1767 for (idx = 0, offset = 0; idx < size-1; idx++) {
1768 elements[idx].Stream = 0;
1769 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1770 elements[idx].Offset = offset;
1771 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1774 *ppVertexElements = elements;
1778 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1779 WINED3DVERTEXELEMENT* elements = NULL;
1780 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1784 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1785 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1787 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1788 HeapFree(GetProcessHeap(), 0, elements);
1789 if (hr != S_OK) return hr;
1794 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1796 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1797 HRESULT hr = WINED3D_OK;
1798 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1799 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1801 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1803 if (vertex_declaration) {
1804 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1807 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1809 if (WINED3D_OK != hr) {
1810 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1811 IWineD3DVertexShader_Release(*ppVertexShader);
1812 return WINED3DERR_INVALIDCALL;
1814 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1819 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1821 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1822 HRESULT hr = WINED3D_OK;
1824 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1825 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1826 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1827 if (WINED3D_OK == hr) {
1828 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1829 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1831 WARN("(%p) : Failed to create pixel shader\n", This);
1837 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1839 IWineD3DPaletteImpl *object;
1841 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1843 /* Create the new object */
1844 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1846 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1847 return E_OUTOFMEMORY;
1850 object->lpVtbl = &IWineD3DPalette_Vtbl;
1852 object->Flags = Flags;
1853 object->parent = Parent;
1854 object->wineD3DDevice = This;
1855 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1857 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1860 HeapFree( GetProcessHeap(), 0, object);
1861 return E_OUTOFMEMORY;
1864 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1866 IWineD3DPalette_Release((IWineD3DPalette *) object);
1870 *Palette = (IWineD3DPalette *) object;
1875 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1879 HDC dcb = NULL, dcs = NULL;
1880 WINEDDCOLORKEY colorkey;
1882 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1885 GetObjectA(hbm, sizeof(BITMAP), &bm);
1886 dcb = CreateCompatibleDC(NULL);
1888 SelectObject(dcb, hbm);
1892 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1893 * couldn't be loaded
1895 memset(&bm, 0, sizeof(bm));
1900 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1901 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1902 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1904 ERR("Wine logo requested, but failed to create surface\n");
1909 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1910 if(FAILED(hr)) goto out;
1911 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1912 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1914 colorkey.dwColorSpaceLowValue = 0;
1915 colorkey.dwColorSpaceHighValue = 0;
1916 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1918 /* Fill the surface with a white color to show that wined3d is there */
1919 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1932 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1934 /* Under DirectX you can have texture stage operations even if no texture is
1935 bound, whereas opengl will only do texture operations when a valid texture is
1936 bound. We emulate this by creating dummy textures and binding them to each
1937 texture stage, but disable all stages by default. Hence if a stage is enabled
1938 then the default texture will kick in until replaced by a SetTexture call */
1941 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1942 /* The dummy texture does not have client storage backing */
1943 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1944 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1946 for (i = 0; i < GL_LIMITS(textures); i++) {
1947 GLubyte white = 255;
1949 /* Make appropriate texture active */
1950 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1951 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1952 checkGLcall("glActiveTextureARB");
1954 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1957 /* Generate an opengl texture name */
1958 glGenTextures(1, &This->dummyTextureName[i]);
1959 checkGLcall("glGenTextures");
1960 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1962 /* Generate a dummy 2d texture (not using 1d because they cause many
1963 * DRI drivers fall back to sw) */
1964 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1965 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1966 checkGLcall("glBindTexture");
1968 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1969 checkGLcall("glTexImage2D");
1971 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1972 /* Reenable because if supported it is enabled by default */
1973 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1974 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
1980 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
1981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1982 IWineD3DSwapChainImpl *swapchain = NULL;
1986 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
1987 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
1989 /* TODO: Test if OpenGL is compiled in and loaded */
1991 TRACE("(%p) : Creating stateblock\n", This);
1992 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
1993 hr = IWineD3DDevice_CreateStateBlock(iface,
1995 (IWineD3DStateBlock **)&This->stateBlock,
1997 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
1998 WARN("Failed to create stateblock\n");
2001 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2002 This->updateStateBlock = This->stateBlock;
2003 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2005 hr = allocate_shader_constants(This->updateStateBlock);
2006 if (WINED3D_OK != hr) {
2010 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2011 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2012 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2014 /* Initialize the texture unit mapping to a 1:1 mapping */
2015 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2016 if (state < GL_LIMITS(fragment_samplers)) {
2017 This->texUnitMap[state] = state;
2018 This->rev_tex_unit_map[state] = state;
2020 This->texUnitMap[state] = -1;
2021 This->rev_tex_unit_map[state] = -1;
2025 /* Setup the implicit swapchain */
2026 TRACE("Creating implicit swapchain\n");
2027 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2028 if (FAILED(hr) || !swapchain) {
2029 WARN("Failed to create implicit swapchain\n");
2033 This->NumberOfSwapChains = 1;
2034 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2035 if(!This->swapchains) {
2036 ERR("Out of memory!\n");
2039 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2041 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2042 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2043 This->render_targets[0] = swapchain->backBuffer[0];
2044 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2047 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2048 This->render_targets[0] = swapchain->frontBuffer;
2049 This->lastActiveRenderTarget = swapchain->frontBuffer;
2051 IWineD3DSurface_AddRef(This->render_targets[0]);
2052 This->activeContext = swapchain->context[0];
2053 This->lastThread = GetCurrentThreadId();
2055 /* Depth Stencil support */
2056 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2057 if (NULL != This->stencilBufferTarget) {
2058 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2061 /* Set up some starting GL setup */
2064 /* Setup all the devices defaults */
2065 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2066 create_dummy_textures(This);
2068 IWineD3DImpl_CheckGraphicsMemory();
2071 { /* Set a default viewport */
2075 vp.Width = pPresentationParameters->BackBufferWidth;
2076 vp.Height = pPresentationParameters->BackBufferHeight;
2079 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2082 /* Initialize the current view state */
2083 This->view_ident = 1;
2084 This->contexts[0]->last_was_rhw = 0;
2085 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2086 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2088 switch(wined3d_settings.offscreen_rendering_mode) {
2091 This->offscreenBuffer = GL_BACK;
2094 case ORM_BACKBUFFER:
2096 if(GL_LIMITS(aux_buffers) > 0) {
2097 TRACE("Using auxilliary buffer for offscreen rendering\n");
2098 This->offscreenBuffer = GL_AUX0;
2100 TRACE("Using back buffer for offscreen rendering\n");
2101 This->offscreenBuffer = GL_BACK;
2106 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2109 /* Clear the screen */
2110 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2111 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2114 This->d3d_initialized = TRUE;
2116 if(wined3d_settings.logo) {
2117 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2122 HeapFree(GetProcessHeap(), 0, This->render_targets);
2123 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2124 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2125 HeapFree(GetProcessHeap(), 0, This->swapchains);
2126 This->NumberOfSwapChains = 0;
2128 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2130 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2131 if(This->stateBlock) {
2132 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2133 This->stateBlock = NULL;
2138 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2139 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2142 TRACE("(%p)\n", This);
2144 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2146 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2147 * it was created. Thus make sure a context is active for the glDelete* calls
2149 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2151 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2153 TRACE("Deleting high order patches\n");
2154 for(i = 0; i < PATCHMAP_SIZE; i++) {
2155 struct list *e1, *e2;
2156 struct WineD3DRectPatch *patch;
2157 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2158 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2159 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2163 /* Delete the palette conversion shader if it is around */
2164 if(This->paletteConversionShader) {
2165 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2166 This->paletteConversionShader = 0;
2169 /* Delete the pbuffer context if there is any */
2170 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2172 /* Delete the mouse cursor texture */
2173 if(This->cursorTexture) {
2175 glDeleteTextures(1, &This->cursorTexture);
2177 This->cursorTexture = 0;
2180 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2181 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2183 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2184 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2187 /* Release the update stateblock */
2188 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2189 if(This->updateStateBlock != This->stateBlock)
2190 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2192 This->updateStateBlock = NULL;
2194 { /* because were not doing proper internal refcounts releasing the primary state block
2195 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2196 to set this->stateBlock = NULL; first */
2197 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2198 This->stateBlock = NULL;
2200 /* Release the stateblock */
2201 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2202 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2206 /* Release the buffers (with sanity checks)*/
2207 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2208 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2209 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2210 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2212 This->stencilBufferTarget = NULL;
2214 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2215 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2216 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2218 TRACE("Setting rendertarget to NULL\n");
2219 This->render_targets[0] = NULL;
2221 if (This->auto_depth_stencil_buffer) {
2222 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2223 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2225 This->auto_depth_stencil_buffer = NULL;
2228 for(i=0; i < This->NumberOfSwapChains; i++) {
2229 TRACE("Releasing the implicit swapchain %d\n", i);
2230 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2231 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2235 HeapFree(GetProcessHeap(), 0, This->swapchains);
2236 This->swapchains = NULL;
2237 This->NumberOfSwapChains = 0;
2239 HeapFree(GetProcessHeap(), 0, This->render_targets);
2240 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2241 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2242 This->render_targets = NULL;
2243 This->fbo_color_attachments = NULL;
2244 This->draw_buffers = NULL;
2247 This->d3d_initialized = FALSE;
2251 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2253 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2255 /* Setup the window for fullscreen mode */
2256 if(fullscreen && !This->ddraw_fullscreen) {
2257 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2258 } else if(!fullscreen && This->ddraw_fullscreen) {
2259 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2262 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2263 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2264 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2267 This->ddraw_fullscreen = fullscreen;
2270 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2271 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2272 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2274 * There is no way to deactivate thread safety once it is enabled.
2276 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2279 /*For now just store the flag(needed in case of ddraw) */
2280 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2285 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2287 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2289 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2292 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2294 /* Resize the screen even without a window:
2295 * The app could have unset it with SetCooperativeLevel, but not called
2296 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2297 * but we don't have any hwnd
2300 memset(&devmode, 0, sizeof(devmode));
2301 devmode.dmSize = sizeof(devmode);
2302 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2303 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2304 devmode.dmPelsWidth = pMode->Width;
2305 devmode.dmPelsHeight = pMode->Height;
2307 devmode.dmDisplayFrequency = pMode->RefreshRate;
2308 if (pMode->RefreshRate != 0) {
2309 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2312 /* Only change the mode if necessary */
2313 if( (This->ddraw_width == pMode->Width) &&
2314 (This->ddraw_height == pMode->Height) &&
2315 (This->ddraw_format == pMode->Format) &&
2316 (pMode->RefreshRate == 0) ) {
2320 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2321 if (ret != DISP_CHANGE_SUCCESSFUL) {
2322 if(devmode.dmDisplayFrequency != 0) {
2323 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2324 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2325 devmode.dmDisplayFrequency = 0;
2326 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2328 if(ret != DISP_CHANGE_SUCCESSFUL) {
2329 return WINED3DERR_NOTAVAILABLE;
2333 /* Store the new values */
2334 This->ddraw_width = pMode->Width;
2335 This->ddraw_height = pMode->Height;
2336 This->ddraw_format = pMode->Format;
2338 /* Only do this with a window of course */
2339 if(This->ddraw_window)
2340 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2342 /* And finally clip mouse to our screen */
2343 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2344 ClipCursor(&clip_rc);
2349 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2351 *ppD3D= This->wineD3D;
2352 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2353 IWineD3D_AddRef(*ppD3D);
2357 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2360 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2361 (This->adapter->TextureRam/(1024*1024)),
2362 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2363 /* return simulated texture memory left */
2364 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2372 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2373 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2375 /* Update the current state block */
2376 This->updateStateBlock->changed.fvf = TRUE;
2378 if(This->updateStateBlock->fvf == fvf) {
2379 TRACE("Application is setting the old fvf over, nothing to do\n");
2383 This->updateStateBlock->fvf = fvf;
2384 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2390 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2392 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2393 *pfvf = This->stateBlock->fvf;
2398 * Get / Set Stream Source
2400 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2402 IWineD3DVertexBuffer *oldSrc;
2404 if (StreamNumber >= MAX_STREAMS) {
2405 WARN("Stream out of range %d\n", StreamNumber);
2406 return WINED3DERR_INVALIDCALL;
2407 } else if(OffsetInBytes & 0x3) {
2408 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2409 return WINED3DERR_INVALIDCALL;
2412 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2413 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2415 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2417 if(oldSrc == pStreamData &&
2418 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2419 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2420 TRACE("Application is setting the old values over, nothing to do\n");
2424 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2426 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2427 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2430 /* Handle recording of state blocks */
2431 if (This->isRecordingState) {
2432 TRACE("Recording... not performing anything\n");
2433 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2434 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2438 /* Need to do a getParent and pass the references up */
2439 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2440 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2441 so for now, just count internally */
2442 if (pStreamData != NULL) {
2443 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2444 InterlockedIncrement(&vbImpl->bindCount);
2445 IWineD3DVertexBuffer_AddRef(pStreamData);
2447 if (oldSrc != NULL) {
2448 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2449 IWineD3DVertexBuffer_Release(oldSrc);
2452 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2457 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2460 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2461 This->stateBlock->streamSource[StreamNumber],
2462 This->stateBlock->streamOffset[StreamNumber],
2463 This->stateBlock->streamStride[StreamNumber]);
2465 if (StreamNumber >= MAX_STREAMS) {
2466 WARN("Stream out of range %d\n", StreamNumber);
2467 return WINED3DERR_INVALIDCALL;
2469 *pStream = This->stateBlock->streamSource[StreamNumber];
2470 *pStride = This->stateBlock->streamStride[StreamNumber];
2472 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2475 if (*pStream != NULL) {
2476 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2481 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2484 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2486 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2487 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2489 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2490 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2492 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2493 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2494 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2500 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2503 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2504 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2506 TRACE("(%p) : returning %d\n", This, *Divider);
2512 * Get / Set & Multiply Transform
2514 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 /* Most of this routine, comments included copied from ddraw tree initially: */
2518 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2520 /* Handle recording of state blocks */
2521 if (This->isRecordingState) {
2522 TRACE("Recording... not performing anything\n");
2523 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2524 memcpy(&This->updateStateBlock->transforms[d3dts], lpmatrix, sizeof(WINED3DMATRIX));
2529 * If the new matrix is the same as the current one,
2530 * we cut off any further processing. this seems to be a reasonable
2531 * optimization because as was noticed, some apps (warcraft3 for example)
2532 * tend towards setting the same matrix repeatedly for some reason.
2534 * From here on we assume that the new matrix is different, wherever it matters.
2536 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2537 TRACE("The app is setting the same matrix over again\n");
2540 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2544 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2545 where ViewMat = Camera space, WorldMat = world space.
2547 In OpenGL, camera and world space is combined into GL_MODELVIEW
2548 matrix. The Projection matrix stay projection matrix.
2551 /* Capture the times we can just ignore the change for now */
2552 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2553 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2554 /* Handled by the state manager */
2557 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2561 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2563 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2564 memcpy(pMatrix, &This->stateBlock->transforms[State], sizeof(WINED3DMATRIX));
2568 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2569 WINED3DMATRIX *mat = NULL;
2572 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2573 * below means it will be recorded in a state block change, but it
2574 * works regardless where it is recorded.
2575 * If this is found to be wrong, change to StateBlock.
2577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2580 if (State < HIGHEST_TRANSFORMSTATE)
2582 mat = &This->updateStateBlock->transforms[State];
2584 FIXME("Unhandled transform state!!\n");
2587 multiply_matrix(&temp, mat, pMatrix);
2589 /* Apply change via set transform - will reapply to eg. lights this way */
2590 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2596 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2597 you can reference any indexes you want as long as that number max are enabled at any
2598 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2599 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2600 but when recording, just build a chain pretty much of commands to be replayed. */
2602 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2604 PLIGHTINFOEL *object = NULL;
2605 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2608 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2609 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2611 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2615 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2616 return WINED3DERR_INVALIDCALL;
2619 switch(pLight->Type) {
2620 case WINED3DLIGHT_POINT:
2621 case WINED3DLIGHT_SPOT:
2622 case WINED3DLIGHT_PARALLELPOINT:
2623 case WINED3DLIGHT_GLSPOT:
2624 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2627 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2628 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2629 return WINED3DERR_INVALIDCALL;
2633 case WINED3DLIGHT_DIRECTIONAL:
2634 /* Ignores attenuation */
2638 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2642 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2643 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2644 if(object->OriginalIndex == Index) break;
2649 TRACE("Adding new light\n");
2650 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2652 ERR("Out of memory error when allocating a light\n");
2653 return E_OUTOFMEMORY;
2655 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2656 object->glIndex = -1;
2657 object->OriginalIndex = Index;
2658 object->changed = TRUE;
2661 /* Initialize the object */
2662 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,
2663 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2664 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2665 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2666 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2667 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2668 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2670 /* Save away the information */
2671 memcpy(&object->OriginalParms, pLight, sizeof(WINED3DLIGHT));
2673 switch (pLight->Type) {
2674 case WINED3DLIGHT_POINT:
2676 object->lightPosn[0] = pLight->Position.x;
2677 object->lightPosn[1] = pLight->Position.y;
2678 object->lightPosn[2] = pLight->Position.z;
2679 object->lightPosn[3] = 1.0f;
2680 object->cutoff = 180.0f;
2684 case WINED3DLIGHT_DIRECTIONAL:
2686 object->lightPosn[0] = -pLight->Direction.x;
2687 object->lightPosn[1] = -pLight->Direction.y;
2688 object->lightPosn[2] = -pLight->Direction.z;
2689 object->lightPosn[3] = 0.0;
2690 object->exponent = 0.0f;
2691 object->cutoff = 180.0f;
2694 case WINED3DLIGHT_SPOT:
2696 object->lightPosn[0] = pLight->Position.x;
2697 object->lightPosn[1] = pLight->Position.y;
2698 object->lightPosn[2] = pLight->Position.z;
2699 object->lightPosn[3] = 1.0;
2702 object->lightDirn[0] = pLight->Direction.x;
2703 object->lightDirn[1] = pLight->Direction.y;
2704 object->lightDirn[2] = pLight->Direction.z;
2705 object->lightDirn[3] = 1.0;
2708 * opengl-ish and d3d-ish spot lights use too different models for the
2709 * light "intensity" as a function of the angle towards the main light direction,
2710 * so we only can approximate very roughly.
2711 * however spot lights are rather rarely used in games (if ever used at all).
2712 * furthermore if still used, probably nobody pays attention to such details.
2714 if (pLight->Falloff == 0) {
2715 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2716 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2717 * will always be 1.0 for both of them, and we don't have to care for the
2718 * rest of the rather complex calculation
2720 object->exponent = 0;
2722 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2723 if (rho < 0.0001) rho = 0.0001f;
2724 object->exponent = -0.3/log(cos(rho/2));
2726 if (object->exponent > 128.0) {
2727 object->exponent = 128.0;
2729 object->cutoff = pLight->Phi*90/M_PI;
2735 FIXME("Unrecognized light type %d\n", pLight->Type);
2738 /* Update the live definitions if the light is currently assigned a glIndex */
2739 if (object->glIndex != -1 && !This->isRecordingState) {
2740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2745 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2746 PLIGHTINFOEL *lightInfo = NULL;
2747 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2748 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2750 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2752 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2753 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2754 if(lightInfo->OriginalIndex == Index) break;
2758 if (lightInfo == NULL) {
2759 TRACE("Light information requested but light not defined\n");
2760 return WINED3DERR_INVALIDCALL;
2763 memcpy(pLight, &lightInfo->OriginalParms, sizeof(WINED3DLIGHT));
2768 * Get / Set Light Enable
2769 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2771 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2772 PLIGHTINFOEL *lightInfo = NULL;
2773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2774 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2776 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2778 /* Tests show true = 128...not clear why */
2779 Enable = Enable? 128: 0;
2781 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2782 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2783 if(lightInfo->OriginalIndex == Index) break;
2786 TRACE("Found light: %p\n", lightInfo);
2788 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2789 if (lightInfo == NULL) {
2791 TRACE("Light enabled requested but light not defined, so defining one!\n");
2792 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2794 /* Search for it again! Should be fairly quick as near head of list */
2795 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2796 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2797 if(lightInfo->OriginalIndex == Index) break;
2800 if (lightInfo == NULL) {
2801 FIXME("Adding default lights has failed dismally\n");
2802 return WINED3DERR_INVALIDCALL;
2806 lightInfo->enabledChanged = TRUE;
2808 if(lightInfo->glIndex != -1) {
2809 if(!This->isRecordingState) {
2810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2813 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2814 lightInfo->glIndex = -1;
2816 TRACE("Light already disabled, nothing to do\n");
2818 lightInfo->enabled = FALSE;
2820 lightInfo->enabled = TRUE;
2821 if (lightInfo->glIndex != -1) {
2823 TRACE("Nothing to do as light was enabled\n");
2826 /* Find a free gl light */
2827 for(i = 0; i < This->maxConcurrentLights; i++) {
2828 if(This->stateBlock->activeLights[i] == NULL) {
2829 This->stateBlock->activeLights[i] = lightInfo;
2830 lightInfo->glIndex = i;
2834 if(lightInfo->glIndex == -1) {
2835 /* Our tests show that Windows returns D3D_OK in this situation, even with
2836 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2837 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2838 * as well for those lights.
2840 * TODO: Test how this affects rendering
2842 FIXME("Too many concurrently active lights\n");
2846 /* i == lightInfo->glIndex */
2847 if(!This->isRecordingState) {
2848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2856 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2858 PLIGHTINFOEL *lightInfo = NULL;
2859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2861 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2862 TRACE("(%p) : for idx(%d)\n", This, Index);
2864 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2865 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2866 if(lightInfo->OriginalIndex == Index) break;
2870 if (lightInfo == NULL) {
2871 TRACE("Light enabled state requested but light not defined\n");
2872 return WINED3DERR_INVALIDCALL;
2874 /* true is 128 according to SetLightEnable */
2875 *pEnable = lightInfo->enabled ? 128 : 0;
2880 * Get / Set Clip Planes
2882 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2884 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2886 /* Validate Index */
2887 if (Index >= GL_LIMITS(clipplanes)) {
2888 TRACE("Application has requested clipplane this device doesn't support\n");
2889 return WINED3DERR_INVALIDCALL;
2892 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2894 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2895 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2896 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2897 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2898 TRACE("Application is setting old values over, nothing to do\n");
2902 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2903 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2904 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2905 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2907 /* Handle recording of state blocks */
2908 if (This->isRecordingState) {
2909 TRACE("Recording... not performing anything\n");
2913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2918 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2920 TRACE("(%p) : for idx %d\n", This, Index);
2922 /* Validate Index */
2923 if (Index >= GL_LIMITS(clipplanes)) {
2924 TRACE("Application has requested clipplane this device doesn't support\n");
2925 return WINED3DERR_INVALIDCALL;
2928 pPlane[0] = This->stateBlock->clipplane[Index][0];
2929 pPlane[1] = This->stateBlock->clipplane[Index][1];
2930 pPlane[2] = This->stateBlock->clipplane[Index][2];
2931 pPlane[3] = This->stateBlock->clipplane[Index][3];
2936 * Get / Set Clip Plane Status
2937 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2939 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2941 FIXME("(%p) : stub\n", This);
2942 if (NULL == pClipStatus) {
2943 return WINED3DERR_INVALIDCALL;
2945 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2946 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2950 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2951 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2952 FIXME("(%p) : stub\n", This);
2953 if (NULL == pClipStatus) {
2954 return WINED3DERR_INVALIDCALL;
2956 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2957 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
2962 * Get / Set Material
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2967 This->updateStateBlock->changed.material = TRUE;
2968 memcpy(&This->updateStateBlock->material, pMaterial, sizeof(WINED3DMATERIAL));
2970 /* Handle recording of state blocks */
2971 if (This->isRecordingState) {
2972 TRACE("Recording... not performing anything\n");
2976 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
2980 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 memcpy(pMaterial, &This->updateStateBlock->material, sizeof (WINED3DMATERIAL));
2983 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
2984 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
2985 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
2986 pMaterial->Ambient.b, pMaterial->Ambient.a);
2987 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
2988 pMaterial->Specular.b, pMaterial->Specular.a);
2989 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
2990 pMaterial->Emissive.b, pMaterial->Emissive.a);
2991 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
2999 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 IWineD3DIndexBuffer *oldIdxs;
3003 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3004 oldIdxs = This->updateStateBlock->pIndexData;
3006 This->updateStateBlock->changed.indices = TRUE;
3007 This->updateStateBlock->pIndexData = pIndexData;
3009 /* Handle recording of state blocks */
3010 if (This->isRecordingState) {
3011 TRACE("Recording... not performing anything\n");
3012 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3013 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3017 if(oldIdxs != pIndexData) {
3018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3019 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3020 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3025 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3028 *ppIndexData = This->stateBlock->pIndexData;
3030 /* up ref count on ppindexdata */
3032 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3033 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3035 TRACE("(%p) No index data set\n", This);
3037 TRACE("Returning %p\n", *ppIndexData);
3042 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3043 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3045 TRACE("(%p)->(%d)\n", This, BaseIndex);
3047 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3048 TRACE("Application is setting the old value over, nothing to do\n");
3052 This->updateStateBlock->baseVertexIndex = BaseIndex;
3054 if (This->isRecordingState) {
3055 TRACE("Recording... not performing anything\n");
3058 /* The base vertex index affects the stream sources */
3059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3063 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3065 TRACE("(%p) : base_index %p\n", This, base_index);
3067 *base_index = This->stateBlock->baseVertexIndex;
3069 TRACE("Returning %u\n", *base_index);
3075 * Get / Set Viewports
3077 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3080 TRACE("(%p)\n", This);
3081 This->updateStateBlock->changed.viewport = TRUE;
3082 memcpy(&This->updateStateBlock->viewport, pViewport, sizeof(WINED3DVIEWPORT));
3084 /* Handle recording of state blocks */
3085 if (This->isRecordingState) {
3086 TRACE("Recording... not performing anything\n");
3090 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3091 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p)\n", This);
3101 memcpy(pViewport, &This->stateBlock->viewport, sizeof(WINED3DVIEWPORT));
3106 * Get / Set Render States
3107 * TODO: Verify against dx9 definitions
3109 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 DWORD oldValue = This->stateBlock->renderState[State];
3114 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3116 This->updateStateBlock->changed.renderState[State] = TRUE;
3117 This->updateStateBlock->renderState[State] = Value;
3119 /* Handle recording of state blocks */
3120 if (This->isRecordingState) {
3121 TRACE("Recording... not performing anything\n");
3125 /* Compared here and not before the assignment to allow proper stateblock recording */
3126 if(Value == oldValue) {
3127 TRACE("Application is setting the old value over, nothing to do\n");
3129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3135 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3136 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3137 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3138 *pValue = This->stateBlock->renderState[State];
3143 * Get / Set Sampler States
3144 * TODO: Verify against dx9 definitions
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3152 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3154 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3155 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3158 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3159 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3160 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3163 * SetSampler is designed to allow for more than the standard up to 8 textures
3164 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3165 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3167 * http://developer.nvidia.com/object/General_FAQ.html#t6
3169 * There are two new settings for GForce
3171 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3172 * and the texture one:
3173 * GL_MAX_TEXTURE_COORDS_ARB.
3174 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3177 oldValue = This->stateBlock->samplerState[Sampler][Type];
3178 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3179 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3181 /* Handle recording of state blocks */
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3187 if(oldValue == Value) {
3188 TRACE("Application is setting the old value over, nothing to do\n");
3192 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3197 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3198 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3200 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3201 This, Sampler, debug_d3dsamplerstate(Type), Type);
3203 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3204 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3207 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3208 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3209 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3211 *Value = This->stateBlock->samplerState[Sampler][Type];
3212 TRACE("(%p) : Returning %#x\n", This, *Value);
3217 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 This->updateStateBlock->changed.scissorRect = TRUE;
3221 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3222 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3225 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3227 if(This->isRecordingState) {
3228 TRACE("Recording... not performing anything\n");
3232 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3237 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 *pRect = This->updateStateBlock->scissorRect;
3241 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3245 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3247 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3249 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3251 This->updateStateBlock->vertexDecl = pDecl;
3252 This->updateStateBlock->changed.vertexDecl = TRUE;
3254 if (This->isRecordingState) {
3255 TRACE("Recording... not performing anything\n");
3257 } else if(pDecl == oldDecl) {
3258 /* Checked after the assignment to allow proper stateblock recording */
3259 TRACE("Application is setting the old declaration over, nothing to do\n");
3263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3267 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3268 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3270 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3272 *ppDecl = This->stateBlock->vertexDecl;
3273 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3277 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3281 This->updateStateBlock->vertexShader = pShader;
3282 This->updateStateBlock->changed.vertexShader = TRUE;
3284 if (This->isRecordingState) {
3285 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3286 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3287 TRACE("Recording... not performing anything\n");
3289 } else if(oldShader == pShader) {
3290 /* Checked here to allow proper stateblock recording */
3291 TRACE("App is setting the old shader over, nothing to do\n");
3295 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3296 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3297 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3299 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3304 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 if (NULL == ppShader) {
3308 return WINED3DERR_INVALIDCALL;
3310 *ppShader = This->stateBlock->vertexShader;
3311 if( NULL != *ppShader)
3312 IWineD3DVertexShader_AddRef(*ppShader);
3314 TRACE("(%p) : returning %p\n", This, *ppShader);
3318 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3319 IWineD3DDevice *iface,
3321 CONST BOOL *srcData,
3324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3325 int i, cnt = min(count, MAX_CONST_B - start);
3327 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3328 iface, srcData, start, count);
3330 if (srcData == NULL || cnt < 0)
3331 return WINED3DERR_INVALIDCALL;
3333 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3334 for (i = 0; i < cnt; i++)
3335 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3337 for (i = start; i < cnt + start; ++i) {
3338 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3341 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3346 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3347 IWineD3DDevice *iface,
3352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3353 int cnt = min(count, MAX_CONST_B - start);
3355 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3356 iface, dstData, start, count);
3358 if (dstData == NULL || cnt < 0)
3359 return WINED3DERR_INVALIDCALL;
3361 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3365 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3366 IWineD3DDevice *iface,
3371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3372 int i, cnt = min(count, MAX_CONST_I - start);
3374 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3375 iface, srcData, start, count);
3377 if (srcData == NULL || cnt < 0)
3378 return WINED3DERR_INVALIDCALL;
3380 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3381 for (i = 0; i < cnt; i++)
3382 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3383 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3385 for (i = start; i < cnt + start; ++i) {
3386 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3395 IWineD3DDevice *iface,
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 int cnt = min(count, MAX_CONST_I - start);
3403 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3404 iface, dstData, start, count);
3406 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3407 return WINED3DERR_INVALIDCALL;
3409 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3413 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3414 IWineD3DDevice *iface,
3416 CONST float *srcData,
3419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3423 iface, srcData, start, count);
3425 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3426 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3427 return WINED3DERR_INVALIDCALL;
3429 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3431 for (i = 0; i < count; i++)
3432 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3433 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3436 for (i = start; i < count + start; ++i) {
3437 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3438 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3439 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3440 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3441 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3443 ptr->idx[ptr->count++] = i;
3444 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3448 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3453 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3454 IWineD3DDevice *iface,
3459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3460 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3462 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3463 iface, dstData, start, count);
3465 if (dstData == NULL || cnt < 0)
3466 return WINED3DERR_INVALIDCALL;
3468 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3472 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3474 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3475 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3479 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3480 int i = This->rev_tex_unit_map[unit];
3481 int j = This->texUnitMap[stage];
3483 This->texUnitMap[stage] = unit;
3484 if (i != -1 && i != stage) {
3485 This->texUnitMap[i] = -1;
3488 This->rev_tex_unit_map[unit] = stage;
3489 if (j != -1 && j != unit) {
3490 This->rev_tex_unit_map[j] = -1;
3494 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3497 for (i = 0; i < MAX_TEXTURES; ++i) {
3498 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3499 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3500 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3501 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3502 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3503 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3504 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3505 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3507 if (color_op == WINED3DTOP_DISABLE) {
3508 /* Not used, and disable higher stages */
3509 while (i < MAX_TEXTURES) {
3510 This->fixed_function_usage_map[i] = FALSE;
3516 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3517 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3518 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3519 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3520 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3521 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3522 This->fixed_function_usage_map[i] = TRUE;
3524 This->fixed_function_usage_map[i] = FALSE;
3527 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3528 This->fixed_function_usage_map[i+1] = TRUE;
3533 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3536 device_update_fixed_function_usage_map(This);
3538 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3539 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3540 if (!This->fixed_function_usage_map[i]) continue;
3542 if (This->texUnitMap[i] != i) {
3543 device_map_stage(This, i, i);
3544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3545 markTextureStagesDirty(This, i);
3551 /* Now work out the mapping */
3553 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3554 if (!This->fixed_function_usage_map[i]) continue;
3556 if (This->texUnitMap[i] != tex) {
3557 device_map_stage(This, i, tex);
3558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3559 markTextureStagesDirty(This, i);
3566 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3567 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3570 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3571 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3572 device_map_stage(This, i, i);
3573 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3574 if (i < MAX_TEXTURES) {
3575 markTextureStagesDirty(This, i);
3581 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3582 int current_mapping = This->rev_tex_unit_map[unit];
3584 if (current_mapping == -1) {
3585 /* Not currently used */
3589 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3590 /* Used by a fragment sampler */
3592 if (!pshader_sampler_tokens) {
3593 /* No pixel shader, check fixed function */
3594 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3597 /* Pixel shader, check the shader's sampler map */
3598 return !pshader_sampler_tokens[current_mapping];
3601 /* Used by a vertex sampler */
3602 return !vshader_sampler_tokens[current_mapping];
3605 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3606 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3607 DWORD *pshader_sampler_tokens = NULL;
3608 int start = GL_LIMITS(combined_samplers) - 1;
3612 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3614 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3615 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3616 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3619 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3620 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3621 if (vshader_sampler_tokens[i]) {
3622 if (This->texUnitMap[vsampler_idx] != -1) {
3623 /* Already mapped somewhere */
3627 while (start >= 0) {
3628 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3629 device_map_stage(This, vsampler_idx, start);
3630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3642 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3643 BOOL vs = use_vs(This);
3644 BOOL ps = use_ps(This);
3647 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3648 * that would be really messy and require shader recompilation
3649 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3650 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3653 device_map_psamplers(This);
3655 device_map_fixed_function_samplers(This);
3659 device_map_vsamplers(This, ps);
3663 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3665 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3666 This->updateStateBlock->pixelShader = pShader;
3667 This->updateStateBlock->changed.pixelShader = TRUE;
3669 /* Handle recording of state blocks */
3670 if (This->isRecordingState) {
3671 TRACE("Recording... not performing anything\n");
3674 if (This->isRecordingState) {
3675 TRACE("Recording... not performing anything\n");
3676 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3677 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3681 if(pShader == oldShader) {
3682 TRACE("App is setting the old pixel shader over, nothing to do\n");
3686 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3687 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3689 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3695 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3698 if (NULL == ppShader) {
3699 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3700 return WINED3DERR_INVALIDCALL;
3703 *ppShader = This->stateBlock->pixelShader;
3704 if (NULL != *ppShader) {
3705 IWineD3DPixelShader_AddRef(*ppShader);
3707 TRACE("(%p) : returning %p\n", This, *ppShader);
3711 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3712 IWineD3DDevice *iface,
3714 CONST BOOL *srcData,
3717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3718 int i, cnt = min(count, MAX_CONST_B - start);
3720 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3721 iface, srcData, start, count);
3723 if (srcData == NULL || cnt < 0)
3724 return WINED3DERR_INVALIDCALL;
3726 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3727 for (i = 0; i < cnt; i++)
3728 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3730 for (i = start; i < cnt + start; ++i) {
3731 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3739 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3740 IWineD3DDevice *iface,
3745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3746 int cnt = min(count, MAX_CONST_B - start);
3748 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3749 iface, dstData, start, count);
3751 if (dstData == NULL || cnt < 0)
3752 return WINED3DERR_INVALIDCALL;
3754 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3758 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3759 IWineD3DDevice *iface,
3764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3765 int i, cnt = min(count, MAX_CONST_I - start);
3767 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3768 iface, srcData, start, count);
3770 if (srcData == NULL || cnt < 0)
3771 return WINED3DERR_INVALIDCALL;
3773 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3774 for (i = 0; i < cnt; i++)
3775 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3776 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3778 for (i = start; i < cnt + start; ++i) {
3779 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3787 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3788 IWineD3DDevice *iface,
3793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3794 int cnt = min(count, MAX_CONST_I - start);
3796 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3797 iface, dstData, start, count);
3799 if (dstData == NULL || cnt < 0)
3800 return WINED3DERR_INVALIDCALL;
3802 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3806 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3807 IWineD3DDevice *iface,
3809 CONST float *srcData,
3812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3815 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3816 iface, srcData, start, count);
3818 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3819 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3820 return WINED3DERR_INVALIDCALL;
3822 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3824 for (i = 0; i < count; i++)
3825 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3826 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3829 for (i = start; i < count + start; ++i) {
3830 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3831 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3832 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3833 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3834 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3836 ptr->idx[ptr->count++] = i;
3837 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3841 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3846 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3847 IWineD3DDevice *iface,
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3853 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3855 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3856 iface, dstData, start, count);
3858 if (dstData == NULL || cnt < 0)
3859 return WINED3DERR_INVALIDCALL;
3861 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3865 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3867 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3868 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3870 DWORD DestFVF = dest->fvf;
3872 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3876 if (lpStrideData->u.s.normal.lpData) {
3877 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3880 if (lpStrideData->u.s.position.lpData == NULL) {
3881 ERR("Source has no position mask\n");
3882 return WINED3DERR_INVALIDCALL;
3885 /* We might access VBOs from this code, so hold the lock */
3888 if (dest->resource.allocatedMemory == NULL) {
3889 /* This may happen if we do direct locking into a vbo. Unlikely,
3890 * but theoretically possible(ddraw processvertices test)
3892 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
3893 if(!dest->resource.allocatedMemory) {
3895 ERR("Out of memory\n");
3896 return E_OUTOFMEMORY;
3900 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
3901 checkGLcall("glBindBufferARB");
3902 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
3904 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
3906 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
3907 checkGLcall("glUnmapBufferARB");
3911 /* Get a pointer into the destination vbo(create one if none exists) and
3912 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
3914 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
3915 dest->Flags |= VBFLAG_CREATEVBO;
3916 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
3920 unsigned char extrabytes = 0;
3921 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
3922 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
3923 * this may write 4 extra bytes beyond the area that should be written
3925 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
3926 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
3927 if(!dest_conv_addr) {
3928 ERR("Out of memory\n");
3929 /* Continue without storing converted vertices */
3931 dest_conv = dest_conv_addr;
3935 * a) WINED3DRS_CLIPPING is enabled
3936 * b) WINED3DVOP_CLIP is passed
3938 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
3939 static BOOL warned = FALSE;
3941 * The clipping code is not quite correct. Some things need
3942 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
3943 * so disable clipping for now.
3944 * (The graphics in Half-Life are broken, and my processvertices
3945 * test crashes with IDirect3DDevice3)
3951 FIXME("Clipping is broken and disabled for now\n");
3953 } else doClip = FALSE;
3954 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
3956 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3959 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3960 WINED3DTS_PROJECTION,
3962 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
3963 WINED3DTS_WORLDMATRIX(0),
3966 TRACE("View mat:\n");
3967 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);
3968 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);
3969 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);
3970 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);
3972 TRACE("Proj mat:\n");
3973 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);
3974 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);
3975 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);
3976 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);
3978 TRACE("World mat:\n");
3979 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);
3980 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);
3981 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);
3982 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);
3984 /* Get the viewport */
3985 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
3986 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
3987 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
3989 multiply_matrix(&mat,&view_mat,&world_mat);
3990 multiply_matrix(&mat,&proj_mat,&mat);
3992 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
3994 for (i = 0; i < dwCount; i+= 1) {
3995 unsigned int tex_index;
3997 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
3998 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
3999 /* The position first */
4001 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4003 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4005 /* Multiplication with world, view and projection matrix */
4006 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);
4007 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);
4008 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);
4009 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);
4011 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4013 /* WARNING: The following things are taken from d3d7 and were not yet checked
4014 * against d3d8 or d3d9!
4017 /* Clipping conditions: From msdn
4019 * A vertex is clipped if it does not match the following requirements
4023 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4025 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4026 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4031 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4032 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4035 /* "Normal" viewport transformation (not clipped)
4036 * 1) The values are divided by rhw
4037 * 2) The y axis is negative, so multiply it with -1
4038 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4039 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4040 * 4) Multiply x with Width/2 and add Width/2
4041 * 5) The same for the height
4042 * 6) Add the viewpoint X and Y to the 2D coordinates and
4043 * The minimum Z value to z
4044 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4046 * Well, basically it's simply a linear transformation into viewport
4058 z *= vp.MaxZ - vp.MinZ;
4060 x += vp.Width / 2 + vp.X;
4061 y += vp.Height / 2 + vp.Y;
4066 /* That vertex got clipped
4067 * Contrary to OpenGL it is not dropped completely, it just
4068 * undergoes a different calculation.
4070 TRACE("Vertex got clipped\n");
4077 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4078 * outside of the main vertex buffer memory. That needs some more
4083 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4086 ( (float *) dest_ptr)[0] = x;
4087 ( (float *) dest_ptr)[1] = y;
4088 ( (float *) dest_ptr)[2] = z;
4089 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4091 dest_ptr += 3 * sizeof(float);
4093 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4094 dest_ptr += sizeof(float);
4099 ( (float *) dest_conv)[0] = x * w;
4100 ( (float *) dest_conv)[1] = y * w;
4101 ( (float *) dest_conv)[2] = z * w;
4102 ( (float *) dest_conv)[3] = w;
4104 dest_conv += 3 * sizeof(float);
4106 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4107 dest_conv += sizeof(float);
4111 if (DestFVF & WINED3DFVF_PSIZE) {
4112 dest_ptr += sizeof(DWORD);
4113 if(dest_conv) dest_conv += sizeof(DWORD);
4115 if (DestFVF & WINED3DFVF_NORMAL) {
4117 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4118 /* AFAIK this should go into the lighting information */
4119 FIXME("Didn't expect the destination to have a normal\n");
4120 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4122 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4126 if (DestFVF & WINED3DFVF_DIFFUSE) {
4128 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4130 static BOOL warned = FALSE;
4133 ERR("No diffuse color in source, but destination has one\n");
4137 *( (DWORD *) dest_ptr) = 0xffffffff;
4138 dest_ptr += sizeof(DWORD);
4141 *( (DWORD *) dest_conv) = 0xffffffff;
4142 dest_conv += sizeof(DWORD);
4146 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4148 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4149 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4150 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4151 dest_conv += sizeof(DWORD);
4156 if (DestFVF & WINED3DFVF_SPECULAR) {
4157 /* What's the color value in the feedback buffer? */
4159 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4161 static BOOL warned = FALSE;
4164 ERR("No specular color in source, but destination has one\n");
4168 *( (DWORD *) dest_ptr) = 0xFF000000;
4169 dest_ptr += sizeof(DWORD);
4172 *( (DWORD *) dest_conv) = 0xFF000000;
4173 dest_conv += sizeof(DWORD);
4177 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4179 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4180 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4181 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4182 dest_conv += sizeof(DWORD);
4187 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4189 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4190 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4192 ERR("No source texture, but destination requests one\n");
4193 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4194 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4197 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4199 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4206 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4207 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4208 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4209 dwCount * get_flexible_vertex_size(DestFVF),
4211 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4212 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4219 #undef copy_and_next
4221 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4222 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4223 WineDirect3DVertexStridedData strided;
4224 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4225 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4228 ERR("Output vertex declaration not implemented yet\n");
4231 /* Need any context to write to the vbo. */
4232 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4234 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4235 * control the streamIsUP flag, thus restore it afterwards.
4237 This->stateBlock->streamIsUP = FALSE;
4238 memset(&strided, 0, sizeof(strided));
4239 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4240 This->stateBlock->streamIsUP = streamWasUP;
4242 if(vbo || SrcStartIndex) {
4244 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4245 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4247 * Also get the start index in, but only loop over all elements if there's something to add at all.
4249 #define FIXSRC(type) \
4250 if(strided.u.s.type.VBO) { \
4251 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4252 strided.u.s.type.VBO = 0; \
4253 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4255 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4259 if(strided.u.s.type.lpData) { \
4260 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4263 FIXSRC(blendWeights);
4264 FIXSRC(blendMatrixIndices);
4269 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4270 FIXSRC(texCoords[i]);
4283 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4287 * Get / Set Texture Stage States
4288 * TODO: Verify against dx9 definitions
4290 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4292 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4294 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4296 if (Stage >= MAX_TEXTURES) {
4297 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4301 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4302 This->updateStateBlock->textureState[Stage][Type] = Value;
4304 if (This->isRecordingState) {
4305 TRACE("Recording... not performing anything\n");
4309 /* Checked after the assignments to allow proper stateblock recording */
4310 if(oldValue == Value) {
4311 TRACE("App is setting the old value over, nothing to do\n");
4315 if(Stage > This->stateBlock->lowest_disabled_stage &&
4316 StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4317 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4318 * Changes in other states are important on disabled stages too
4323 if(Type == WINED3DTSS_COLOROP) {
4326 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4327 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4328 * they have to be disabled
4330 * The current stage is dirtified below.
4332 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4333 TRACE("Additionally dirtifying stage %d\n", i);
4334 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4336 This->stateBlock->lowest_disabled_stage = Stage;
4337 TRACE("New lowest disabled: %d\n", Stage);
4338 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4339 /* Previously disabled stage enabled. Stages above it may need enabling
4340 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4341 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4343 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4346 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4347 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4350 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4351 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4353 This->stateBlock->lowest_disabled_stage = i;
4354 TRACE("New lowest disabled: %d\n", i);
4356 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4357 /* TODO: Built a stage -> texture unit mapping for register combiners */
4361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4366 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4368 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4369 *pValue = This->updateStateBlock->textureState[Stage][Type];
4376 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4377 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4378 IWineD3DBaseTexture *oldTexture;
4380 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4382 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4383 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4386 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4387 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4388 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4391 oldTexture = This->updateStateBlock->textures[Stage];
4393 if(pTexture != NULL) {
4394 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4396 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4397 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4398 return WINED3DERR_INVALIDCALL;
4400 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4403 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4404 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4406 This->updateStateBlock->changed.textures[Stage] = TRUE;
4407 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4408 This->updateStateBlock->textures[Stage] = pTexture;
4410 /* Handle recording of state blocks */
4411 if (This->isRecordingState) {
4412 TRACE("Recording... not performing anything\n");
4416 if(oldTexture == pTexture) {
4417 TRACE("App is setting the same texture again, nothing to do\n");
4421 /** NOTE: MSDN says that setTexture increases the reference count,
4422 * and that the application must set the texture back to null (or have a leaky application),
4423 * This means we should pass the refcount up to the parent
4424 *******************************/
4425 if (NULL != This->updateStateBlock->textures[Stage]) {
4426 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4427 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4429 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4430 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4431 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4432 * so the COLOROP and ALPHAOP have to be dirtified.
4434 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4435 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4437 if(bindCount == 1) {
4438 new->baseTexture.sampler = Stage;
4440 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4444 if (NULL != oldTexture) {
4445 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4446 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4448 IWineD3DBaseTexture_Release(oldTexture);
4449 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4451 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4454 if(bindCount && old->baseTexture.sampler == Stage) {
4456 /* Have to do a search for the other sampler(s) where the texture is bound to
4457 * Shouldn't happen as long as apps bind a texture only to one stage
4459 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4460 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4461 if(This->updateStateBlock->textures[i] == oldTexture) {
4462 old->baseTexture.sampler = i;
4469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4474 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4479 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4480 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4483 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4484 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4485 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4488 *ppTexture=This->stateBlock->textures[Stage];
4490 IWineD3DBaseTexture_AddRef(*ppTexture);
4492 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4500 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4501 IWineD3DSurface **ppBackBuffer) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 IWineD3DSwapChain *swapChain;
4506 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4508 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4509 if (hr == WINED3D_OK) {
4510 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4511 IWineD3DSwapChain_Release(swapChain);
4513 *ppBackBuffer = NULL;
4518 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 WARN("(%p) : stub, calling idirect3d for now\n", This);
4521 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4524 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4525 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4526 IWineD3DSwapChain *swapChain;
4529 if(iSwapChain > 0) {
4530 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4531 if (hr == WINED3D_OK) {
4532 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4533 IWineD3DSwapChain_Release(swapChain);
4535 FIXME("(%p) Error getting display mode\n", This);
4538 /* Don't read the real display mode,
4539 but return the stored mode instead. X11 can't change the color
4540 depth, and some apps are pretty angry if they SetDisplayMode from
4541 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4543 Also don't relay to the swapchain because with ddraw it's possible
4544 that there isn't a swapchain at all */
4545 pMode->Width = This->ddraw_width;
4546 pMode->Height = This->ddraw_height;
4547 pMode->Format = This->ddraw_format;
4548 pMode->RefreshRate = 0;
4555 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4557 TRACE("(%p)->(%p)\n", This, hWnd);
4559 if(This->ddraw_fullscreen) {
4560 if(This->ddraw_window && This->ddraw_window != hWnd) {
4561 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4563 if(hWnd && This->ddraw_window != hWnd) {
4564 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4568 This->ddraw_window = hWnd;
4572 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4573 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4574 TRACE("(%p)->(%p)\n", This, hWnd);
4576 *hWnd = This->ddraw_window;
4581 * Stateblock related functions
4584 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 IWineD3DStateBlockImpl *object;
4587 HRESULT temp_result;
4590 TRACE("(%p)\n", This);
4592 if (This->isRecordingState) {
4593 return WINED3DERR_INVALIDCALL;
4596 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4597 if (NULL == object ) {
4598 FIXME("(%p)Error allocating memory for stateblock\n", This);
4599 return E_OUTOFMEMORY;
4601 TRACE("(%p) created object %p\n", This, object);
4602 object->wineD3DDevice= This;
4603 /** FIXME: object->parent = parent; **/
4604 object->parent = NULL;
4605 object->blockType = WINED3DSBT_RECORDED;
4607 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4609 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4610 list_init(&object->lightMap[i]);
4613 temp_result = allocate_shader_constants(object);
4614 if (WINED3D_OK != temp_result)
4617 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4618 This->updateStateBlock = object;
4619 This->isRecordingState = TRUE;
4621 TRACE("(%p) recording stateblock %p\n",This , object);
4625 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4630 if (!This->isRecordingState) {
4631 FIXME("(%p) not recording! returning error\n", This);
4632 *ppStateBlock = NULL;
4633 return WINED3DERR_INVALIDCALL;
4636 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4637 if(object->changed.renderState[i]) {
4638 object->contained_render_states[object->num_contained_render_states] = i;
4639 object->num_contained_render_states++;
4642 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4643 if(object->changed.transform[i]) {
4644 object->contained_transform_states[object->num_contained_transform_states] = i;
4645 object->num_contained_transform_states++;
4648 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4649 if(object->changed.vertexShaderConstantsF[i]) {
4650 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4651 object->num_contained_vs_consts_f++;
4654 for(i = 0; i < MAX_CONST_I; i++) {
4655 if(object->changed.vertexShaderConstantsI[i]) {
4656 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4657 object->num_contained_vs_consts_i++;
4660 for(i = 0; i < MAX_CONST_B; i++) {
4661 if(object->changed.vertexShaderConstantsB[i]) {
4662 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4663 object->num_contained_vs_consts_b++;
4666 for(i = 0; i < MAX_CONST_I; i++) {
4667 if(object->changed.pixelShaderConstantsI[i]) {
4668 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4669 object->num_contained_ps_consts_i++;
4672 for(i = 0; i < MAX_CONST_B; i++) {
4673 if(object->changed.pixelShaderConstantsB[i]) {
4674 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4675 object->num_contained_ps_consts_b++;
4678 for(i = 0; i < MAX_TEXTURES; i++) {
4679 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4680 if(object->changed.textureState[i][j]) {
4681 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4682 object->contained_tss_states[object->num_contained_tss_states].state = j;
4683 object->num_contained_tss_states++;
4687 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4688 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4689 if(object->changed.samplerState[i][j]) {
4690 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4691 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4692 object->num_contained_sampler_states++;
4697 *ppStateBlock = (IWineD3DStateBlock*) object;
4698 This->isRecordingState = FALSE;
4699 This->updateStateBlock = This->stateBlock;
4700 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4701 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4702 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4707 * Scene related functions
4709 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4710 /* At the moment we have no need for any functionality at the beginning
4712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4713 TRACE("(%p)\n", This);
4716 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4717 return WINED3DERR_INVALIDCALL;
4719 This->inScene = TRUE;
4723 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 TRACE("(%p)\n", This);
4727 if(!This->inScene) {
4728 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4729 return WINED3DERR_INVALIDCALL;
4732 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4733 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4736 checkGLcall("glFlush");
4739 This->inScene = FALSE;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4744 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4745 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4746 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4747 IWineD3DSwapChain *swapChain = NULL;
4749 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4751 TRACE("(%p) Presenting the frame\n", This);
4753 for(i = 0 ; i < swapchains ; i ++) {
4755 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4756 TRACE("presentinng chain %d, %p\n", i, swapChain);
4757 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4758 IWineD3DSwapChain_Release(swapChain);
4764 /* Not called from the VTable (internal subroutine) */
4765 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4766 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4767 float Z, DWORD Stencil) {
4768 GLbitfield glMask = 0;
4770 WINED3DRECT curRect;
4772 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4773 UINT drawable_width, drawable_height;
4774 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4776 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4777 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4778 * for the cleared parts, and the untouched parts.
4780 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4781 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4782 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4783 * checking all this if the dest surface is in the drawable anyway.
4785 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4787 if(vp->X != 0 || vp->Y != 0 ||
4788 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4789 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4792 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4793 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4794 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4795 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4796 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4799 if(Count > 0 && pRects && (
4800 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4801 pRects[0].x2 < target->currentDesc.Width ||
4802 pRects[0].y2 < target->currentDesc.Height)) {
4803 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4810 target->get_drawable_size(target, &drawable_width, &drawable_height);
4812 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4815 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4816 apply_fbo_state((IWineD3DDevice *) This);
4819 /* Only set the values up once, as they are not changing */
4820 if (Flags & WINED3DCLEAR_STENCIL) {
4821 glClearStencil(Stencil);
4822 checkGLcall("glClearStencil");
4823 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4824 glStencilMask(0xFFFFFFFF);
4827 if (Flags & WINED3DCLEAR_ZBUFFER) {
4828 glDepthMask(GL_TRUE);
4830 checkGLcall("glClearDepth");
4831 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4832 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4834 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4835 if(vp->X != 0 || vp->Y != 0 ||
4836 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4837 depth_copy((IWineD3DDevice *) This);
4839 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4840 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4841 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4842 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4843 depth_copy((IWineD3DDevice *) This);
4845 else if(Count > 0 && pRects && (
4846 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4847 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4848 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4849 depth_copy((IWineD3DDevice *) This);
4852 This->depth_copy_state = WINED3D_DCS_INITIAL;
4855 if (Flags & WINED3DCLEAR_TARGET) {
4856 TRACE("Clearing screen with glClear to color %x\n", Color);
4857 glClearColor(D3DCOLOR_R(Color),
4861 checkGLcall("glClearColor");
4863 /* Clear ALL colors! */
4864 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4865 glMask = glMask | GL_COLOR_BUFFER_BIT;
4868 vp_rect.left = vp->X;
4869 vp_rect.top = vp->Y;
4870 vp_rect.right = vp->X + vp->Width;
4871 vp_rect.bottom = vp->Y + vp->Height;
4872 if (!(Count > 0 && pRects)) {
4873 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4874 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4876 if(This->render_offscreen) {
4877 glScissor(vp_rect.left, vp_rect.top,
4878 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4880 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4881 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4883 checkGLcall("glScissor");
4885 checkGLcall("glClear");
4887 /* Now process each rect in turn */
4888 for (i = 0; i < Count; i++) {
4889 /* Note gl uses lower left, width/height */
4890 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
4891 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4892 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
4894 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
4895 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
4896 curRect.x1, (target->currentDesc.Height - curRect.y2),
4897 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4899 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
4900 * The rectangle is not cleared, no error is returned, but further rectanlges are
4901 * still cleared if they are valid
4903 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
4904 TRACE("Rectangle with negative dimensions, ignoring\n");
4908 if(This->render_offscreen) {
4909 glScissor(curRect.x1, curRect.y1,
4910 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4912 glScissor(curRect.x1, drawable_height - curRect.y2,
4913 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
4915 checkGLcall("glScissor");
4918 checkGLcall("glClear");
4922 /* Restore the old values (why..?) */
4923 if (Flags & WINED3DCLEAR_STENCIL) {
4924 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
4926 if (Flags & WINED3DCLEAR_TARGET) {
4927 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
4928 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
4929 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
4930 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
4931 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
4933 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
4934 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
4936 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
4937 /* TODO: Move the fbo logic into ModifyLocation() */
4938 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4939 target->Flags |= SFLAG_INTEXTURE;
4947 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
4948 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4950 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
4952 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
4953 Count, pRects, Flags, Color, Z, Stencil);
4955 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
4956 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
4957 /* TODO: What about depth stencil buffers without stencil bits? */
4958 return WINED3DERR_INVALIDCALL;
4961 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
4967 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
4968 UINT PrimitiveCount) {
4970 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4972 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
4973 debug_d3dprimitivetype(PrimitiveType),
4974 StartVertex, PrimitiveCount);
4976 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
4977 if(This->stateBlock->streamIsUP) {
4978 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
4979 This->stateBlock->streamIsUP = FALSE;
4982 if(This->stateBlock->loadBaseVertexIndex != 0) {
4983 This->stateBlock->loadBaseVertexIndex = 0;
4984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
4986 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
4987 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
4988 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
4992 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
4993 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
4994 WINED3DPRIMITIVETYPE PrimitiveType,
4995 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
4997 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4999 IWineD3DIndexBuffer *pIB;
5000 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5003 pIB = This->stateBlock->pIndexData;
5005 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5006 * without an index buffer set. (The first time at least...)
5007 * D3D8 simply dies, but I doubt it can do much harm to return
5008 * D3DERR_INVALIDCALL there as well. */
5009 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5010 return WINED3DERR_INVALIDCALL;
5013 if(This->stateBlock->streamIsUP) {
5014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5015 This->stateBlock->streamIsUP = FALSE;
5017 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5019 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5020 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5021 minIndex, NumVertices, startIndex, primCount);
5023 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5024 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5030 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5031 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5032 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5035 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5036 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5041 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5042 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5043 UINT VertexStreamZeroStride) {
5044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5045 IWineD3DVertexBuffer *vb;
5047 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5048 debug_d3dprimitivetype(PrimitiveType),
5049 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5051 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5052 vb = This->stateBlock->streamSource[0];
5053 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5054 if(vb) IWineD3DVertexBuffer_Release(vb);
5055 This->stateBlock->streamOffset[0] = 0;
5056 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5057 This->stateBlock->streamIsUP = TRUE;
5058 This->stateBlock->loadBaseVertexIndex = 0;
5060 /* TODO: Only mark dirty if drawing from a different UP address */
5061 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5063 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5064 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5066 /* MSDN specifies stream zero settings must be set to NULL */
5067 This->stateBlock->streamStride[0] = 0;
5068 This->stateBlock->streamSource[0] = NULL;
5070 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5071 * the new stream sources or use UP drawing again
5076 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5077 UINT MinVertexIndex, UINT NumVertices,
5078 UINT PrimitiveCount, CONST void* pIndexData,
5079 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5080 UINT VertexStreamZeroStride) {
5082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5083 IWineD3DVertexBuffer *vb;
5084 IWineD3DIndexBuffer *ib;
5086 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5087 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5088 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5089 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5091 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5097 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5098 vb = This->stateBlock->streamSource[0];
5099 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5100 if(vb) IWineD3DVertexBuffer_Release(vb);
5101 This->stateBlock->streamIsUP = TRUE;
5102 This->stateBlock->streamOffset[0] = 0;
5103 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5105 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5106 This->stateBlock->baseVertexIndex = 0;
5107 This->stateBlock->loadBaseVertexIndex = 0;
5108 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5109 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5110 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5112 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5114 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5115 This->stateBlock->streamSource[0] = NULL;
5116 This->stateBlock->streamStride[0] = 0;
5117 ib = This->stateBlock->pIndexData;
5119 IWineD3DIndexBuffer_Release(ib);
5120 This->stateBlock->pIndexData = NULL;
5122 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5123 * SetStreamSource to specify a vertex buffer
5129 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5132 /* Mark the state dirty until we have nicer tracking
5133 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5137 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5138 This->stateBlock->baseVertexIndex = 0;
5139 This->up_strided = DrawPrimStrideData;
5140 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5141 This->up_strided = NULL;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5147 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5149 /* Mark the state dirty until we have nicer tracking
5150 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5153 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5154 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5155 This->stateBlock->streamIsUP = TRUE;
5156 This->stateBlock->baseVertexIndex = 0;
5157 This->up_strided = DrawPrimStrideData;
5158 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5159 This->up_strided = NULL;
5163 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5164 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5165 * not callable by the app directly no parameter validation checks are needed here.
5167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5168 WINED3DLOCKED_BOX src;
5169 WINED3DLOCKED_BOX dst;
5171 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5173 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5174 * dirtification to improve loading performance.
5176 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5177 if(FAILED(hr)) return hr;
5178 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5180 IWineD3DVolume_UnlockBox(pSourceVolume);
5184 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5186 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5188 IWineD3DVolume_UnlockBox(pSourceVolume);
5190 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5195 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5196 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5198 HRESULT hr = WINED3D_OK;
5199 WINED3DRESOURCETYPE sourceType;
5200 WINED3DRESOURCETYPE destinationType;
5203 /* TODO: think about moving the code into IWineD3DBaseTexture */
5205 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5207 /* verify that the source and destination textures aren't NULL */
5208 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5209 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5210 This, pSourceTexture, pDestinationTexture);
5211 hr = WINED3DERR_INVALIDCALL;
5214 if (pSourceTexture == pDestinationTexture) {
5215 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5216 This, pSourceTexture, pDestinationTexture);
5217 hr = WINED3DERR_INVALIDCALL;
5219 /* Verify that the source and destination textures are the same type */
5220 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5221 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5223 if (sourceType != destinationType) {
5224 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5226 hr = WINED3DERR_INVALIDCALL;
5229 /* check that both textures have the identical numbers of levels */
5230 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5231 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5232 hr = WINED3DERR_INVALIDCALL;
5235 if (WINED3D_OK == hr) {
5237 /* Make sure that the destination texture is loaded */
5238 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5240 /* Update every surface level of the texture */
5241 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5243 switch (sourceType) {
5244 case WINED3DRTYPE_TEXTURE:
5246 IWineD3DSurface *srcSurface;
5247 IWineD3DSurface *destSurface;
5249 for (i = 0 ; i < levels ; ++i) {
5250 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5251 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5252 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5253 IWineD3DSurface_Release(srcSurface);
5254 IWineD3DSurface_Release(destSurface);
5255 if (WINED3D_OK != hr) {
5256 WARN("(%p) : Call to update surface failed\n", This);
5262 case WINED3DRTYPE_CUBETEXTURE:
5264 IWineD3DSurface *srcSurface;
5265 IWineD3DSurface *destSurface;
5266 WINED3DCUBEMAP_FACES faceType;
5268 for (i = 0 ; i < levels ; ++i) {
5269 /* Update each cube face */
5270 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5271 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5272 if (WINED3D_OK != hr) {
5273 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5275 TRACE("Got srcSurface %p\n", srcSurface);
5277 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5278 if (WINED3D_OK != hr) {
5279 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5281 TRACE("Got desrSurface %p\n", destSurface);
5283 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5284 IWineD3DSurface_Release(srcSurface);
5285 IWineD3DSurface_Release(destSurface);
5286 if (WINED3D_OK != hr) {
5287 WARN("(%p) : Call to update surface failed\n", This);
5295 case WINED3DRTYPE_VOLUMETEXTURE:
5297 IWineD3DVolume *srcVolume = NULL;
5298 IWineD3DVolume *destVolume = NULL;
5300 for (i = 0 ; i < levels ; ++i) {
5301 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5302 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5303 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5304 IWineD3DVolume_Release(srcVolume);
5305 IWineD3DVolume_Release(destVolume);
5306 if (WINED3D_OK != hr) {
5307 WARN("(%p) : Call to update volume failed\n", This);
5315 FIXME("(%p) : Unsupported source and destination type\n", This);
5316 hr = WINED3DERR_INVALIDCALL;
5323 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5324 IWineD3DSwapChain *swapChain;
5326 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5327 if(hr == WINED3D_OK) {
5328 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5329 IWineD3DSwapChain_Release(swapChain);
5334 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5336 /* return a sensible default */
5338 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5339 FIXME("(%p) : stub\n", This);
5343 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5346 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5347 if (PaletteNumber >= MAX_PALETTES) {
5348 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5349 return WINED3DERR_INVALIDCALL;
5351 for (j = 0; j < 256; ++j) {
5352 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5353 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5354 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5355 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5357 TRACE("(%p) : returning\n", This);
5361 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5364 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5365 if (PaletteNumber >= MAX_PALETTES) {
5366 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5367 return WINED3DERR_INVALIDCALL;
5369 for (j = 0; j < 256; ++j) {
5370 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5371 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5372 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5373 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5375 TRACE("(%p) : returning\n", This);
5379 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5380 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5381 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5382 if (PaletteNumber >= MAX_PALETTES) {
5383 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5384 return WINED3DERR_INVALIDCALL;
5386 /*TODO: stateblocks */
5387 This->currentPalette = PaletteNumber;
5388 TRACE("(%p) : returning\n", This);
5392 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5394 if (PaletteNumber == NULL) {
5395 WARN("(%p) : returning Invalid Call\n", This);
5396 return WINED3DERR_INVALIDCALL;
5398 /*TODO: stateblocks */
5399 *PaletteNumber = This->currentPalette;
5400 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5404 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5406 static BOOL showFixmes = TRUE;
5408 FIXME("(%p) : stub\n", This);
5412 This->softwareVertexProcessing = bSoftware;
5417 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5419 static BOOL showFixmes = TRUE;
5421 FIXME("(%p) : stub\n", This);
5424 return This->softwareVertexProcessing;
5428 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5430 IWineD3DSwapChain *swapChain;
5433 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5435 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5436 if(hr == WINED3D_OK){
5437 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5438 IWineD3DSwapChain_Release(swapChain);
5440 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5446 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5448 static BOOL showfixmes = TRUE;
5449 if(nSegments != 0.0f) {
5451 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5458 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5460 static BOOL showfixmes = TRUE;
5462 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5468 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5470 /** TODO: remove casts to IWineD3DSurfaceImpl
5471 * NOTE: move code to surface to accomplish this
5472 ****************************************/
5473 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5474 int srcWidth, srcHeight;
5475 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5476 WINED3DFORMAT destFormat, srcFormat;
5478 int srcLeft, destLeft, destTop;
5479 WINED3DPOOL srcPool, destPool;
5481 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5482 glDescriptor *glDescription = NULL;
5485 CONVERT_TYPES convert = NO_CONVERSION;
5487 WINED3DSURFACE_DESC winedesc;
5489 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5490 memset(&winedesc, 0, sizeof(winedesc));
5491 winedesc.Width = &srcSurfaceWidth;
5492 winedesc.Height = &srcSurfaceHeight;
5493 winedesc.Pool = &srcPool;
5494 winedesc.Format = &srcFormat;
5496 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5498 winedesc.Width = &destSurfaceWidth;
5499 winedesc.Height = &destSurfaceHeight;
5500 winedesc.Pool = &destPool;
5501 winedesc.Format = &destFormat;
5502 winedesc.Size = &destSize;
5504 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5506 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5507 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5508 return WINED3DERR_INVALIDCALL;
5511 /* This call loads the opengl surface directly, instead of copying the surface to the
5512 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5513 * copy in sysmem and use regular surface loading.
5515 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5516 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5517 if(convert != NO_CONVERSION) {
5518 return IWineD3DSurface_BltFast(pDestinationSurface,
5519 pDestPoint ? pDestPoint->x : 0,
5520 pDestPoint ? pDestPoint->y : 0,
5521 pSourceSurface, (RECT *) pSourceRect, 0);
5524 if (destFormat == WINED3DFMT_UNKNOWN) {
5525 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5526 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5528 /* Get the update surface description */
5529 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5532 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5536 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5537 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5538 checkGLcall("glActiveTextureARB");
5541 /* Make sure the surface is loaded and up to date */
5542 IWineD3DSurface_PreLoad(pDestinationSurface);
5544 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5546 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5547 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5548 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5549 srcLeft = pSourceRect ? pSourceRect->left : 0;
5550 destLeft = pDestPoint ? pDestPoint->x : 0;
5551 destTop = pDestPoint ? pDestPoint->y : 0;
5554 /* This function doesn't support compressed textures
5555 the pitch is just bytesPerPixel * width */
5556 if(srcWidth != srcSurfaceWidth || srcLeft ){
5557 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5558 offset += srcLeft * pSrcSurface->bytesPerPixel;
5559 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5561 /* TODO DXT formats */
5563 if(pSourceRect != NULL && pSourceRect->top != 0){
5564 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5566 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5568 ,glDescription->level
5573 ,glDescription->glFormat
5574 ,glDescription->glType
5575 ,IWineD3DSurface_GetData(pSourceSurface)
5579 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5581 /* need to lock the surface to get the data */
5582 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5585 /* TODO: Cube and volume support */
5587 /* not a whole row so we have to do it a line at a time */
5590 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5591 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5593 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5595 glTexSubImage2D(glDescription->target
5596 ,glDescription->level
5601 ,glDescription->glFormat
5602 ,glDescription->glType
5603 ,data /* could be quicker using */
5608 } else { /* Full width, so just write out the whole texture */
5610 if (WINED3DFMT_DXT1 == destFormat ||
5611 WINED3DFMT_DXT2 == destFormat ||
5612 WINED3DFMT_DXT3 == destFormat ||
5613 WINED3DFMT_DXT4 == destFormat ||
5614 WINED3DFMT_DXT5 == destFormat) {
5615 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5616 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5617 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5618 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5619 } if (destFormat != srcFormat) {
5620 FIXME("Updating mixed format compressed texture is not curretly support\n");
5622 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5623 glDescription->level,
5624 glDescription->glFormatInternal,
5629 IWineD3DSurface_GetData(pSourceSurface));
5632 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5637 glTexSubImage2D(glDescription->target
5638 ,glDescription->level
5643 ,glDescription->glFormat
5644 ,glDescription->glType
5645 ,IWineD3DSurface_GetData(pSourceSurface)
5649 checkGLcall("glTexSubImage2D");
5653 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5654 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5659 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 struct WineD3DRectPatch *patch;
5665 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5667 if(!(Handle || pRectPatchInfo)) {
5668 /* TODO: Write a test for the return value, thus the FIXME */
5669 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5670 return WINED3DERR_INVALIDCALL;
5674 i = PATCHMAP_HASHFUNC(Handle);
5676 LIST_FOR_EACH(e, &This->patches[i]) {
5677 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5678 if(patch->Handle == Handle) {
5685 TRACE("Patch does not exist. Creating a new one\n");
5686 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5687 patch->Handle = Handle;
5688 list_add_head(&This->patches[i], &patch->entry);
5690 TRACE("Found existing patch %p\n", patch);
5693 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5694 * attributes we have to tesselate, read back, and draw. This needs a patch
5695 * management structure instance. Create one.
5697 * A possible improvement is to check if a vertex shader is used, and if not directly
5700 FIXME("Drawing an uncached patch. This is slow\n");
5701 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5704 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5705 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5706 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5708 TRACE("Tesselation density or patch info changed, retesselating\n");
5710 if(pRectPatchInfo) {
5711 memcpy(&patch->RectPatchInfo, pRectPatchInfo, sizeof(*pRectPatchInfo));
5713 patch->numSegs[0] = pNumSegs[0];
5714 patch->numSegs[1] = pNumSegs[1];
5715 patch->numSegs[2] = pNumSegs[2];
5716 patch->numSegs[3] = pNumSegs[3];
5718 hr = tesselate_rectpatch(This, patch);
5720 WARN("Patch tesselation failed\n");
5722 /* Do not release the handle to store the params of the patch */
5724 HeapFree(GetProcessHeap(), 0, patch);
5730 This->currentPatch = patch;
5731 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5732 This->currentPatch = NULL;
5734 /* Destroy uncached patches */
5736 HeapFree(GetProcessHeap(), 0, patch->mem);
5737 HeapFree(GetProcessHeap(), 0, patch);
5742 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5745 FIXME("(%p) : Stub\n", This);
5749 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 struct WineD3DRectPatch *patch;
5754 TRACE("(%p) Handle(%d)\n", This, Handle);
5756 i = PATCHMAP_HASHFUNC(Handle);
5757 LIST_FOR_EACH(e, &This->patches[i]) {
5758 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5759 if(patch->Handle == Handle) {
5760 TRACE("Deleting patch %p\n", patch);
5761 list_remove(&patch->entry);
5762 HeapFree(GetProcessHeap(), 0, patch->mem);
5763 HeapFree(GetProcessHeap(), 0, patch);
5768 /* TODO: Write a test for the return value */
5769 FIXME("Attempt to destroy nonexistent patch\n");
5770 return WINED3DERR_INVALIDCALL;
5773 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5775 IWineD3DSwapChain *swapchain;
5777 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5778 if (SUCCEEDED(hr)) {
5779 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5786 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5790 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5791 checkGLcall("glGenFramebuffersEXT()");
5793 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5794 checkGLcall("glBindFramebuffer()");
5797 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5798 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5799 IWineD3DBaseTextureImpl *texture_impl;
5800 GLenum texttarget, target;
5803 texttarget = surface_impl->glDescription.target;
5804 if(texttarget == GL_TEXTURE_2D) {
5805 target = GL_TEXTURE_2D;
5806 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5807 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5808 target = GL_TEXTURE_RECTANGLE_ARB;
5809 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5811 target = GL_TEXTURE_CUBE_MAP_ARB;
5812 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5815 IWineD3DSurface_PreLoad(surface);
5817 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5818 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5819 glBindTexture(target, old_binding);
5821 /* Update base texture states array */
5822 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5823 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5824 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5825 if (texture_impl->baseTexture.bindCount) {
5826 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5829 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5832 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5833 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5835 checkGLcall("attach_surface_fbo");
5838 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5840 IWineD3DSwapChain *swapchain;
5842 swapchain = get_swapchain(surface);
5846 TRACE("Surface %p is onscreen\n", surface);
5848 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5849 buffer = surface_get_gl_buffer(surface, swapchain);
5850 glDrawBuffer(buffer);
5851 checkGLcall("glDrawBuffer()");
5853 TRACE("Surface %p is offscreen\n", surface);
5854 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5855 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5859 glEnable(GL_SCISSOR_TEST);
5861 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5863 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5864 rect->x2 - rect->x1, rect->y2 - rect->y1);
5866 checkGLcall("glScissor");
5868 glDisable(GL_SCISSOR_TEST);
5870 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5872 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5873 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5875 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5876 glClear(GL_COLOR_BUFFER_BIT);
5877 checkGLcall("glClear");
5879 if (This->render_offscreen) {
5880 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5882 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5883 checkGLcall("glBindFramebuffer()");
5886 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5887 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5888 glDrawBuffer(GL_BACK);
5889 checkGLcall("glDrawBuffer()");
5893 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
5894 unsigned int r, g, b, a;
5897 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
5898 destfmt == WINED3DFMT_R8G8B8)
5901 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
5903 a = (color & 0xff000000) >> 24;
5904 r = (color & 0x00ff0000) >> 16;
5905 g = (color & 0x0000ff00) >> 8;
5906 b = (color & 0x000000ff) >> 0;
5910 case WINED3DFMT_R5G6B5:
5911 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
5918 TRACE("Returning %08x\n", ret);
5921 case WINED3DFMT_X1R5G5B5:
5922 case WINED3DFMT_A1R5G5B5:
5931 TRACE("Returning %08x\n", ret);
5935 TRACE("Returning %08x\n", a);
5938 case WINED3DFMT_X4R4G4B4:
5939 case WINED3DFMT_A4R4G4B4:
5948 TRACE("Returning %08x\n", ret);
5951 case WINED3DFMT_R3G3B2:
5958 TRACE("Returning %08x\n", ret);
5961 case WINED3DFMT_X8B8G8R8:
5962 case WINED3DFMT_A8B8G8R8:
5967 TRACE("Returning %08x\n", ret);
5970 case WINED3DFMT_A2R10G10B10:
5972 r = (r * 1024) / 256;
5973 g = (g * 1024) / 256;
5974 b = (b * 1024) / 256;
5979 TRACE("Returning %08x\n", ret);
5982 case WINED3DFMT_A2B10G10R10:
5984 r = (r * 1024) / 256;
5985 g = (g * 1024) / 256;
5986 b = (b * 1024) / 256;
5991 TRACE("Returning %08x\n", ret);
5995 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6000 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6002 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6004 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6006 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6007 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6008 return WINED3DERR_INVALIDCALL;
6011 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6012 color_fill_fbo(iface, pSurface, pRect, color);
6015 /* Just forward this to the DirectDraw blitting engine */
6016 memset(&BltFx, 0, sizeof(BltFx));
6017 BltFx.dwSize = sizeof(BltFx);
6018 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6019 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6023 /* rendertarget and depth stencil functions */
6024 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6027 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6028 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6029 return WINED3DERR_INVALIDCALL;
6032 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6033 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6034 /* Note inc ref on returned surface */
6035 if(*ppRenderTarget != NULL)
6036 IWineD3DSurface_AddRef(*ppRenderTarget);
6040 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6042 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6043 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6044 IWineD3DSwapChainImpl *Swapchain;
6047 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6049 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6050 if(hr != WINED3D_OK) {
6051 ERR("Can't get the swapchain\n");
6055 /* Make sure to release the swapchain */
6056 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6058 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6059 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6060 return WINED3DERR_INVALIDCALL;
6062 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6063 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6064 return WINED3DERR_INVALIDCALL;
6067 if(Swapchain->frontBuffer != Front) {
6068 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6070 if(Swapchain->frontBuffer)
6071 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6072 Swapchain->frontBuffer = Front;
6074 if(Swapchain->frontBuffer) {
6075 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6079 if(Back && !Swapchain->backBuffer) {
6080 /* We need memory for the back buffer array - only one back buffer this way */
6081 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6082 if(!Swapchain->backBuffer) {
6083 ERR("Out of memory\n");
6084 return E_OUTOFMEMORY;
6088 if(Swapchain->backBuffer[0] != Back) {
6089 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6091 /* What to do about the context here in the case of multithreading? Not sure.
6092 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6095 if(!Swapchain->backBuffer[0]) {
6096 /* GL was told to draw to the front buffer at creation,
6099 glDrawBuffer(GL_BACK);
6100 checkGLcall("glDrawBuffer(GL_BACK)");
6101 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6102 Swapchain->presentParms.BackBufferCount = 1;
6104 /* That makes problems - disable for now */
6105 /* glDrawBuffer(GL_FRONT); */
6106 checkGLcall("glDrawBuffer(GL_FRONT)");
6107 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6108 Swapchain->presentParms.BackBufferCount = 0;
6112 if(Swapchain->backBuffer[0])
6113 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6114 Swapchain->backBuffer[0] = Back;
6116 if(Swapchain->backBuffer[0]) {
6117 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6119 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6120 Swapchain->backBuffer = NULL;
6128 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6129 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6130 *ppZStencilSurface = This->stencilBufferTarget;
6131 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6133 if(*ppZStencilSurface != NULL) {
6134 /* Note inc ref on returned surface */
6135 IWineD3DSurface_AddRef(*ppZStencilSurface);
6138 return WINED3DERR_NOTFOUND;
6142 /* TODO: Handle stencil attachments */
6143 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6145 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6147 TRACE("Set depth stencil to %p\n", depth_stencil);
6149 if (depth_stencil_impl) {
6150 if (depth_stencil_impl->current_renderbuffer) {
6151 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6152 checkGLcall("glFramebufferRenderbufferEXT()");
6154 IWineD3DBaseTextureImpl *texture_impl;
6155 GLenum texttarget, target;
6156 GLint old_binding = 0;
6158 texttarget = depth_stencil_impl->glDescription.target;
6159 if(texttarget == GL_TEXTURE_2D) {
6160 target = GL_TEXTURE_2D;
6161 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6162 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6163 target = GL_TEXTURE_RECTANGLE_ARB;
6164 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6166 target = GL_TEXTURE_CUBE_MAP_ARB;
6167 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6170 IWineD3DSurface_PreLoad(depth_stencil);
6172 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6173 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6174 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6175 glBindTexture(target, old_binding);
6177 /* Update base texture states array */
6178 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6179 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6180 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6181 if (texture_impl->baseTexture.bindCount) {
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6185 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6188 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6189 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6190 checkGLcall("glFramebufferTexture2DEXT()");
6193 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6194 checkGLcall("glFramebufferTexture2DEXT()");
6198 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6199 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6200 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6202 TRACE("Set render target %u to %p\n", idx, render_target);
6205 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6206 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6208 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6209 checkGLcall("glFramebufferTexture2DEXT()");
6211 This->draw_buffers[idx] = GL_NONE;
6215 static void check_fbo_status(IWineD3DDevice *iface) {
6216 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6219 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6220 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6221 TRACE("FBO complete\n");
6223 IWineD3DSurfaceImpl *attachment;
6225 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6227 /* Dump the FBO attachments */
6228 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6229 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6231 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6232 attachment->pow2Width, attachment->pow2Height);
6235 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6237 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6238 attachment->pow2Width, attachment->pow2Height);
6243 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6245 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6246 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6248 if (!ds_impl) return FALSE;
6250 if (ds_impl->current_renderbuffer) {
6251 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6252 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6255 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6256 rt_impl->pow2Height != ds_impl->pow2Height);
6259 void apply_fbo_state(IWineD3DDevice *iface) {
6260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6263 if (This->render_offscreen) {
6264 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6266 /* Apply render targets */
6267 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6268 IWineD3DSurface *render_target = This->render_targets[i];
6269 if (This->fbo_color_attachments[i] != render_target) {
6270 set_render_target_fbo(iface, i, render_target);
6271 This->fbo_color_attachments[i] = render_target;
6275 /* Apply depth targets */
6276 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6277 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6278 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6280 if (This->stencilBufferTarget) {
6281 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6283 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6284 This->fbo_depth_attachment = This->stencilBufferTarget;
6287 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6288 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6289 checkGLcall("glDrawBuffers()");
6291 glDrawBuffer(This->draw_buffers[0]);
6292 checkGLcall("glDrawBuffer()");
6295 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6298 check_fbo_status(iface);
6301 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6302 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6304 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6305 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6308 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6309 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6310 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6311 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6314 case WINED3DTEXF_LINEAR:
6315 gl_filter = GL_LINEAR;
6319 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6320 case WINED3DTEXF_NONE:
6321 case WINED3DTEXF_POINT:
6322 gl_filter = GL_NEAREST;
6326 /* Attach src surface to src fbo */
6327 src_swapchain = get_swapchain(src_surface);
6328 if (src_swapchain) {
6331 TRACE("Source surface %p is onscreen\n", src_surface);
6332 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6333 /* Make sure the drawable is up to date. In the offscreen case
6334 * attach_surface_fbo() implicitly takes care of this. */
6335 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6338 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6339 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6340 glReadBuffer(buffer);
6341 checkGLcall("glReadBuffer()");
6343 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6344 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6346 TRACE("Source surface %p is offscreen\n", src_surface);
6348 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6349 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6350 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6351 checkGLcall("glReadBuffer()");
6355 /* Attach dst surface to dst fbo */
6356 dst_swapchain = get_swapchain(dst_surface);
6357 if (dst_swapchain) {
6360 TRACE("Destination surface %p is onscreen\n", dst_surface);
6361 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6362 /* Make sure the drawable is up to date. In the offscreen case
6363 * attach_surface_fbo() implicitly takes care of this. */
6364 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6367 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6368 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6369 glDrawBuffer(buffer);
6370 checkGLcall("glDrawBuffer()");
6372 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6373 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6375 TRACE("Destination surface %p is offscreen\n", dst_surface);
6377 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6378 if(!src_swapchain) {
6379 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6383 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6384 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6385 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6386 checkGLcall("glDrawBuffer()");
6388 glDisable(GL_SCISSOR_TEST);
6389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6392 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6393 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6394 checkGLcall("glBlitFramebuffer()");
6396 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6397 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6398 checkGLcall("glBlitFramebuffer()");
6401 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6403 if (This->render_offscreen) {
6404 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6406 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6407 checkGLcall("glBindFramebuffer()");
6410 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6411 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6412 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6413 glDrawBuffer(GL_BACK);
6414 checkGLcall("glDrawBuffer()");
6419 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6421 WINED3DVIEWPORT viewport;
6423 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6425 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6426 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6427 This, RenderTargetIndex, GL_LIMITS(buffers));
6428 return WINED3DERR_INVALIDCALL;
6431 /* MSDN says that null disables the render target
6432 but a device must always be associated with a render target
6433 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6435 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6436 FIXME("Trying to set render target 0 to NULL\n");
6437 return WINED3DERR_INVALIDCALL;
6439 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6440 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);
6441 return WINED3DERR_INVALIDCALL;
6444 /* If we are trying to set what we already have, don't bother */
6445 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6446 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6449 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6450 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6451 This->render_targets[RenderTargetIndex] = pRenderTarget;
6453 /* Render target 0 is special */
6454 if(RenderTargetIndex == 0) {
6455 /* Finally, reset the viewport as the MSDN states. */
6456 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6457 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6460 viewport.MaxZ = 1.0f;
6461 viewport.MinZ = 0.0f;
6462 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6463 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6464 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6466 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6468 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6470 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6471 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6473 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6478 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6480 HRESULT hr = WINED3D_OK;
6481 IWineD3DSurface *tmp;
6483 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6485 if (pNewZStencil == This->stencilBufferTarget) {
6486 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6488 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6489 * depending on the renter target implementation being used.
6490 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6491 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6492 * stencil buffer and incur an extra memory overhead
6493 ******************************************************/
6495 tmp = This->stencilBufferTarget;
6496 This->stencilBufferTarget = pNewZStencil;
6497 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6498 /* should we be calling the parent or the wined3d surface? */
6499 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6500 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6503 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6504 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6505 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6506 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6507 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6514 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6515 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6517 /* TODO: the use of Impl is deprecated. */
6518 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6519 WINED3DLOCKED_RECT lockedRect;
6521 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6523 /* some basic validation checks */
6524 if(This->cursorTexture) {
6525 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6527 glDeleteTextures(1, &This->cursorTexture);
6529 This->cursorTexture = 0;
6532 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6533 This->haveHardwareCursor = TRUE;
6535 This->haveHardwareCursor = FALSE;
6538 WINED3DLOCKED_RECT rect;
6540 /* MSDN: Cursor must be A8R8G8B8 */
6541 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6542 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6543 return WINED3DERR_INVALIDCALL;
6546 /* MSDN: Cursor must be smaller than the display mode */
6547 if(pSur->currentDesc.Width > This->ddraw_width ||
6548 pSur->currentDesc.Height > This->ddraw_height) {
6549 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);
6550 return WINED3DERR_INVALIDCALL;
6553 if (!This->haveHardwareCursor) {
6554 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6556 /* Do not store the surface's pointer because the application may
6557 * release it after setting the cursor image. Windows doesn't
6558 * addref the set surface, so we can't do this either without
6559 * creating circular refcount dependencies. Copy out the gl texture
6562 This->cursorWidth = pSur->currentDesc.Width;
6563 This->cursorHeight = pSur->currentDesc.Height;
6564 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6566 const GlPixelFormatDesc *glDesc;
6567 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6568 char *mem, *bits = (char *)rect.pBits;
6569 GLint intfmt = glDesc->glInternal;
6570 GLint format = glDesc->glFormat;
6571 GLint type = glDesc->glType;
6572 INT height = This->cursorHeight;
6573 INT width = This->cursorWidth;
6574 INT bpp = tableEntry->bpp;
6577 /* Reformat the texture memory (pitch and width can be
6579 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6580 for(i = 0; i < height; i++)
6581 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6582 IWineD3DSurface_UnlockRect(pCursorBitmap);
6585 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6586 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6587 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6590 /* Make sure that a proper texture unit is selected */
6591 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6592 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6593 checkGLcall("glActiveTextureARB");
6595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6596 /* Create a new cursor texture */
6597 glGenTextures(1, &This->cursorTexture);
6598 checkGLcall("glGenTextures");
6599 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6600 checkGLcall("glBindTexture");
6601 /* Copy the bitmap memory into the cursor texture */
6602 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6603 HeapFree(GetProcessHeap(), 0, mem);
6604 checkGLcall("glTexImage2D");
6606 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6607 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6608 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6615 FIXME("A cursor texture was not returned.\n");
6616 This->cursorTexture = 0;
6621 /* Draw a hardware cursor */
6622 ICONINFO cursorInfo;
6624 /* Create and clear maskBits because it is not needed for
6625 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6627 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6628 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6629 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6630 WINED3DLOCK_NO_DIRTY_UPDATE |
6631 WINED3DLOCK_READONLY
6633 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6634 pSur->currentDesc.Height);
6636 cursorInfo.fIcon = FALSE;
6637 cursorInfo.xHotspot = XHotSpot;
6638 cursorInfo.yHotspot = YHotSpot;
6639 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6640 pSur->currentDesc.Height, 1,
6642 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6643 pSur->currentDesc.Height, 1,
6644 32, lockedRect.pBits);
6645 IWineD3DSurface_UnlockRect(pCursorBitmap);
6646 /* Create our cursor and clean up. */
6647 cursor = CreateIconIndirect(&cursorInfo);
6649 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6650 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6651 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6652 This->hardwareCursor = cursor;
6653 HeapFree(GetProcessHeap(), 0, maskBits);
6657 This->xHotSpot = XHotSpot;
6658 This->yHotSpot = YHotSpot;
6662 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6664 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6666 This->xScreenSpace = XScreenSpace;
6667 This->yScreenSpace = YScreenSpace;
6673 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6675 BOOL oldVisible = This->bCursorVisible;
6678 TRACE("(%p) : visible(%d)\n", This, bShow);
6681 * When ShowCursor is first called it should make the cursor appear at the OS's last
6682 * known cursor position. Because of this, some applications just repetitively call
6683 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6686 This->xScreenSpace = pt.x;
6687 This->yScreenSpace = pt.y;
6689 if (This->haveHardwareCursor) {
6690 This->bCursorVisible = bShow;
6692 SetCursor(This->hardwareCursor);
6698 if (This->cursorTexture)
6699 This->bCursorVisible = bShow;
6705 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6707 IWineD3DResourceImpl *resource;
6708 TRACE("(%p) : state (%u)\n", This, This->state);
6710 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6711 switch (This->state) {
6714 case WINED3DERR_DEVICELOST:
6716 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6717 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6718 return WINED3DERR_DEVICENOTRESET;
6720 return WINED3DERR_DEVICELOST;
6722 case WINED3DERR_DRIVERINTERNALERROR:
6723 return WINED3DERR_DRIVERINTERNALERROR;
6727 return WINED3DERR_DRIVERINTERNALERROR;
6731 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6733 /** FIXME: Resource tracking needs to be done,
6734 * The closes we can do to this is set the priorities of all managed textures low
6735 * and then reset them.
6736 ***********************************************************/
6737 FIXME("(%p) : stub\n", This);
6741 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6742 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6744 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6745 if(surface->Flags & SFLAG_DIBSECTION) {
6746 /* Release the DC */
6747 SelectObject(surface->hDC, surface->dib.holdbitmap);
6748 DeleteDC(surface->hDC);
6749 /* Release the DIB section */
6750 DeleteObject(surface->dib.DIBsection);
6751 surface->dib.bitmap_data = NULL;
6752 surface->resource.allocatedMemory = NULL;
6753 surface->Flags &= ~SFLAG_DIBSECTION;
6755 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6756 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6757 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6758 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6759 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6761 surface->pow2Width = surface->pow2Height = 1;
6762 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6763 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6765 surface->glRect.left = 0;
6766 surface->glRect.top = 0;
6767 surface->glRect.right = surface->pow2Width;
6768 surface->glRect.bottom = surface->pow2Height;
6770 if(surface->glDescription.textureName) {
6771 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6773 glDeleteTextures(1, &surface->glDescription.textureName);
6775 surface->glDescription.textureName = 0;
6776 surface->Flags &= ~SFLAG_CLIENT;
6778 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6779 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6780 surface->Flags |= SFLAG_NONPOW2;
6782 surface->Flags &= ~SFLAG_NONPOW2;
6784 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6785 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6788 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6789 TRACE("Unloading resource %p\n", resource);
6790 IWineD3DResource_UnLoad(resource);
6791 IWineD3DResource_Release(resource);
6795 static void reset_fbo_state(IWineD3DDevice *iface) {
6796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6800 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6801 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6804 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6807 if (This->src_fbo) {
6808 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6811 if (This->dst_fbo) {
6812 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6815 checkGLcall("Tear down fbos\n");
6818 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6819 This->fbo_color_attachments[i] = NULL;
6821 This->fbo_depth_attachment = NULL;
6824 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6826 WINED3DDISPLAYMODE m;
6829 /* All Windowed modes are supported, as is leaving the current mode */
6830 if(pp->Windowed) return TRUE;
6831 if(!pp->BackBufferWidth) return TRUE;
6832 if(!pp->BackBufferHeight) return TRUE;
6834 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6835 for(i = 0; i < count; i++) {
6836 memset(&m, 0, sizeof(m));
6837 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6839 ERR("EnumAdapterModes failed\n");
6841 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6842 /* Mode found, it is supported */
6846 /* Mode not found -> not supported */
6850 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6852 IWineD3DSwapChainImpl *swapchain;
6854 BOOL DisplayModeChanged = FALSE;
6855 WINED3DDISPLAYMODE mode;
6856 IWineD3DBaseShaderImpl *shader;
6857 IWineD3DSurfaceImpl *target;
6859 TRACE("(%p)\n", This);
6861 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6863 ERR("Failed to get the first implicit swapchain\n");
6867 if(!is_display_mode_supported(This, pPresentationParameters)) {
6868 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6869 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6870 pPresentationParameters->BackBufferHeight);
6871 return WINED3DERR_INVALIDCALL;
6874 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6875 * on an existing gl context, so there's no real need for recreation.
6877 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6879 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6881 TRACE("New params:\n");
6882 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6883 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6884 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6885 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6886 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6887 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6888 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6889 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6890 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
6891 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
6892 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
6893 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
6894 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
6896 /* No special treatment of these parameters. Just store them */
6897 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
6898 swapchain->presentParms.Flags = pPresentationParameters->Flags;
6899 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
6900 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
6902 /* What to do about these? */
6903 if(pPresentationParameters->BackBufferCount != 0 &&
6904 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
6905 ERR("Cannot change the back buffer count yet\n");
6907 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
6908 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
6909 ERR("Cannot change the back buffer format yet\n");
6911 if(pPresentationParameters->hDeviceWindow != NULL &&
6912 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
6913 ERR("Cannot change the device window yet\n");
6915 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
6916 ERR("What do do about a changed auto depth stencil parameter?\n");
6919 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6920 reset_fbo_state((IWineD3DDevice *) This);
6923 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6924 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6925 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6929 if(This->depth_blt_texture) {
6930 glDeleteTextures(1, &This->depth_blt_texture);
6931 This->depth_blt_texture = 0;
6933 This->shader_backend->shader_destroy_depth_blt(iface);
6935 for (i = 0; i < GL_LIMITS(textures); i++) {
6936 /* Textures are recreated below */
6937 glDeleteTextures(1, &This->dummyTextureName[i]);
6938 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6939 This->dummyTextureName[i] = 0;
6943 while(This->numContexts) {
6944 DestroyContext(This, This->contexts[0]);
6946 This->activeContext = NULL;
6947 HeapFree(GetProcessHeap(), 0, swapchain->context);
6948 swapchain->context = NULL;
6949 swapchain->num_contexts = 0;
6951 if(pPresentationParameters->Windowed) {
6952 mode.Width = swapchain->orig_width;
6953 mode.Height = swapchain->orig_height;
6954 mode.RefreshRate = 0;
6955 mode.Format = swapchain->presentParms.BackBufferFormat;
6957 mode.Width = pPresentationParameters->BackBufferWidth;
6958 mode.Height = pPresentationParameters->BackBufferHeight;
6959 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
6960 mode.Format = swapchain->presentParms.BackBufferFormat;
6963 /* Should Width == 800 && Height == 0 set 800x600? */
6964 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
6965 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
6966 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
6973 vp.Width = pPresentationParameters->BackBufferWidth;
6974 vp.Height = pPresentationParameters->BackBufferHeight;
6978 if(!pPresentationParameters->Windowed) {
6979 DisplayModeChanged = TRUE;
6981 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
6982 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
6984 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
6985 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
6986 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
6988 if(This->auto_depth_stencil_buffer) {
6989 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
6993 /* Now set the new viewport */
6994 IWineD3DDevice_SetViewport(iface, &vp);
6997 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
6998 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
6999 DisplayModeChanged) {
7001 /* Switching to fullscreen? Change to fullscreen mode, THEN change the screen res */
7002 if(!pPresentationParameters->Windowed) {
7003 IWineD3DDevice_SetFullscreen(iface, TRUE);
7006 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7008 /* Switching out of fullscreen mode? First set the original res, then change the window */
7009 if(pPresentationParameters->Windowed) {
7010 IWineD3DDevice_SetFullscreen(iface, FALSE);
7012 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7013 } else if(!pPresentationParameters->Windowed) {
7014 DWORD style = This->style, exStyle = This->exStyle;
7015 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7016 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7017 * Reset to clear up their mess. Guild Wars also loses the device during that.
7021 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7022 This->style = style;
7023 This->exStyle = exStyle;
7026 /* Recreate the primary swapchain's context */
7027 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7028 if(swapchain->backBuffer) {
7029 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7031 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7033 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7034 &swapchain->presentParms);
7035 swapchain->num_contexts = 1;
7036 This->activeContext = swapchain->context[0];
7038 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7040 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7042 create_dummy_textures(This);
7044 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7048 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7052 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7053 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7054 /** FIXME: always true at the moment **/
7055 if(!bEnableDialogs) {
7056 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7062 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7064 TRACE("(%p) : pParameters %p\n", This, pParameters);
7066 *pParameters = This->createParms;
7070 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7071 IWineD3DSwapChain *swapchain;
7072 HRESULT hrc = WINED3D_OK;
7074 TRACE("Relaying to swapchain\n");
7076 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7077 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7078 IWineD3DSwapChain_Release(swapchain);
7083 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7084 IWineD3DSwapChain *swapchain;
7085 HRESULT hrc = WINED3D_OK;
7087 TRACE("Relaying to swapchain\n");
7089 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7090 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7091 IWineD3DSwapChain_Release(swapchain);
7097 /** ********************************************************
7098 * Notification functions
7099 ** ********************************************************/
7100 /** This function must be called in the release of a resource when ref == 0,
7101 * the contents of resource must still be correct,
7102 * any handles to other resource held by the caller must be closed
7103 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7104 *****************************************************/
7105 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7108 TRACE("(%p) : Adding Resource %p\n", This, resource);
7109 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7112 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7115 TRACE("(%p) : Removing resource %p\n", This, resource);
7117 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7121 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7125 TRACE("(%p) : resource %p\n", This, resource);
7126 switch(IWineD3DResource_GetType(resource)){
7127 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7128 case WINED3DRTYPE_SURFACE: {
7131 /* Cleanup any FBO attachments if d3d is enabled */
7132 if(This->d3d_initialized) {
7133 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7134 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7136 TRACE("Last active render target destroyed\n");
7137 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7138 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7139 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7140 * and the lastActiveRenderTarget member shouldn't matter
7143 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7144 TRACE("Activating primary back buffer\n");
7145 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7146 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7147 /* Single buffering environment */
7148 TRACE("Activating primary front buffer\n");
7149 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7151 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7152 /* Implicit render target destroyed, that means the device is being destroyed
7153 * whatever we set here, it shouldn't matter
7155 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7158 /* May happen during ddraw uninitialization */
7159 TRACE("Render target set, but swapchain does not exist!\n");
7160 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7164 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7165 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7166 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7167 set_render_target_fbo(iface, i, NULL);
7168 This->fbo_color_attachments[i] = NULL;
7171 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7172 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7173 set_depth_stencil_fbo(iface, NULL);
7174 This->fbo_depth_attachment = NULL;
7180 case WINED3DRTYPE_TEXTURE:
7181 case WINED3DRTYPE_CUBETEXTURE:
7182 case WINED3DRTYPE_VOLUMETEXTURE:
7183 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7184 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7185 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7186 This->stateBlock->textures[counter] = NULL;
7188 if (This->updateStateBlock != This->stateBlock ){
7189 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7190 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7191 This->updateStateBlock->textures[counter] = NULL;
7196 case WINED3DRTYPE_VOLUME:
7197 /* TODO: nothing really? */
7199 case WINED3DRTYPE_VERTEXBUFFER:
7200 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7203 TRACE("Cleaning up stream pointers\n");
7205 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7206 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7207 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7209 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7210 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7211 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7212 This->updateStateBlock->streamSource[streamNumber] = 0;
7213 /* Set changed flag? */
7216 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) */
7217 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7218 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7219 This->stateBlock->streamSource[streamNumber] = 0;
7222 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7223 else { /* This shouldn't happen */
7224 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7231 case WINED3DRTYPE_INDEXBUFFER:
7232 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7233 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7234 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7235 This->updateStateBlock->pIndexData = NULL;
7238 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7239 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7240 This->stateBlock->pIndexData = NULL;
7246 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7251 /* Remove the resource from the resourceStore */
7252 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7254 TRACE("Resource released\n");
7258 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7259 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7260 IWineD3DResourceImpl *resource, *cursor;
7262 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7264 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7265 TRACE("enumerating resource %p\n", resource);
7266 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7267 ret = pCallback((IWineD3DResource *) resource, pData);
7268 if(ret == S_FALSE) {
7269 TRACE("Canceling enumeration\n");
7276 /**********************************************************
7277 * IWineD3DDevice VTbl follows
7278 **********************************************************/
7280 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7282 /*** IUnknown methods ***/
7283 IWineD3DDeviceImpl_QueryInterface,
7284 IWineD3DDeviceImpl_AddRef,
7285 IWineD3DDeviceImpl_Release,
7286 /*** IWineD3DDevice methods ***/
7287 IWineD3DDeviceImpl_GetParent,
7288 /*** Creation methods**/
7289 IWineD3DDeviceImpl_CreateVertexBuffer,
7290 IWineD3DDeviceImpl_CreateIndexBuffer,
7291 IWineD3DDeviceImpl_CreateStateBlock,
7292 IWineD3DDeviceImpl_CreateSurface,
7293 IWineD3DDeviceImpl_CreateTexture,
7294 IWineD3DDeviceImpl_CreateVolumeTexture,
7295 IWineD3DDeviceImpl_CreateVolume,
7296 IWineD3DDeviceImpl_CreateCubeTexture,
7297 IWineD3DDeviceImpl_CreateQuery,
7298 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7299 IWineD3DDeviceImpl_CreateVertexDeclaration,
7300 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7301 IWineD3DDeviceImpl_CreateVertexShader,
7302 IWineD3DDeviceImpl_CreatePixelShader,
7303 IWineD3DDeviceImpl_CreatePalette,
7304 /*** Odd functions **/
7305 IWineD3DDeviceImpl_Init3D,
7306 IWineD3DDeviceImpl_Uninit3D,
7307 IWineD3DDeviceImpl_SetFullscreen,
7308 IWineD3DDeviceImpl_SetMultithreaded,
7309 IWineD3DDeviceImpl_EvictManagedResources,
7310 IWineD3DDeviceImpl_GetAvailableTextureMem,
7311 IWineD3DDeviceImpl_GetBackBuffer,
7312 IWineD3DDeviceImpl_GetCreationParameters,
7313 IWineD3DDeviceImpl_GetDeviceCaps,
7314 IWineD3DDeviceImpl_GetDirect3D,
7315 IWineD3DDeviceImpl_GetDisplayMode,
7316 IWineD3DDeviceImpl_SetDisplayMode,
7317 IWineD3DDeviceImpl_GetHWND,
7318 IWineD3DDeviceImpl_SetHWND,
7319 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7320 IWineD3DDeviceImpl_GetRasterStatus,
7321 IWineD3DDeviceImpl_GetSwapChain,
7322 IWineD3DDeviceImpl_Reset,
7323 IWineD3DDeviceImpl_SetDialogBoxMode,
7324 IWineD3DDeviceImpl_SetCursorProperties,
7325 IWineD3DDeviceImpl_SetCursorPosition,
7326 IWineD3DDeviceImpl_ShowCursor,
7327 IWineD3DDeviceImpl_TestCooperativeLevel,
7328 /*** Getters and setters **/
7329 IWineD3DDeviceImpl_SetClipPlane,
7330 IWineD3DDeviceImpl_GetClipPlane,
7331 IWineD3DDeviceImpl_SetClipStatus,
7332 IWineD3DDeviceImpl_GetClipStatus,
7333 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7334 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7335 IWineD3DDeviceImpl_SetDepthStencilSurface,
7336 IWineD3DDeviceImpl_GetDepthStencilSurface,
7337 IWineD3DDeviceImpl_SetFVF,
7338 IWineD3DDeviceImpl_GetFVF,
7339 IWineD3DDeviceImpl_SetGammaRamp,
7340 IWineD3DDeviceImpl_GetGammaRamp,
7341 IWineD3DDeviceImpl_SetIndices,
7342 IWineD3DDeviceImpl_GetIndices,
7343 IWineD3DDeviceImpl_SetBaseVertexIndex,
7344 IWineD3DDeviceImpl_GetBaseVertexIndex,
7345 IWineD3DDeviceImpl_SetLight,
7346 IWineD3DDeviceImpl_GetLight,
7347 IWineD3DDeviceImpl_SetLightEnable,
7348 IWineD3DDeviceImpl_GetLightEnable,
7349 IWineD3DDeviceImpl_SetMaterial,
7350 IWineD3DDeviceImpl_GetMaterial,
7351 IWineD3DDeviceImpl_SetNPatchMode,
7352 IWineD3DDeviceImpl_GetNPatchMode,
7353 IWineD3DDeviceImpl_SetPaletteEntries,
7354 IWineD3DDeviceImpl_GetPaletteEntries,
7355 IWineD3DDeviceImpl_SetPixelShader,
7356 IWineD3DDeviceImpl_GetPixelShader,
7357 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7358 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7359 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7360 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7361 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7362 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7363 IWineD3DDeviceImpl_SetRenderState,
7364 IWineD3DDeviceImpl_GetRenderState,
7365 IWineD3DDeviceImpl_SetRenderTarget,
7366 IWineD3DDeviceImpl_GetRenderTarget,
7367 IWineD3DDeviceImpl_SetFrontBackBuffers,
7368 IWineD3DDeviceImpl_SetSamplerState,
7369 IWineD3DDeviceImpl_GetSamplerState,
7370 IWineD3DDeviceImpl_SetScissorRect,
7371 IWineD3DDeviceImpl_GetScissorRect,
7372 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7373 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7374 IWineD3DDeviceImpl_SetStreamSource,
7375 IWineD3DDeviceImpl_GetStreamSource,
7376 IWineD3DDeviceImpl_SetStreamSourceFreq,
7377 IWineD3DDeviceImpl_GetStreamSourceFreq,
7378 IWineD3DDeviceImpl_SetTexture,
7379 IWineD3DDeviceImpl_GetTexture,
7380 IWineD3DDeviceImpl_SetTextureStageState,
7381 IWineD3DDeviceImpl_GetTextureStageState,
7382 IWineD3DDeviceImpl_SetTransform,
7383 IWineD3DDeviceImpl_GetTransform,
7384 IWineD3DDeviceImpl_SetVertexDeclaration,
7385 IWineD3DDeviceImpl_GetVertexDeclaration,
7386 IWineD3DDeviceImpl_SetVertexShader,
7387 IWineD3DDeviceImpl_GetVertexShader,
7388 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7389 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7390 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7391 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7392 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7393 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7394 IWineD3DDeviceImpl_SetViewport,
7395 IWineD3DDeviceImpl_GetViewport,
7396 IWineD3DDeviceImpl_MultiplyTransform,
7397 IWineD3DDeviceImpl_ValidateDevice,
7398 IWineD3DDeviceImpl_ProcessVertices,
7399 /*** State block ***/
7400 IWineD3DDeviceImpl_BeginStateBlock,
7401 IWineD3DDeviceImpl_EndStateBlock,
7402 /*** Scene management ***/
7403 IWineD3DDeviceImpl_BeginScene,
7404 IWineD3DDeviceImpl_EndScene,
7405 IWineD3DDeviceImpl_Present,
7406 IWineD3DDeviceImpl_Clear,
7408 IWineD3DDeviceImpl_DrawPrimitive,
7409 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7410 IWineD3DDeviceImpl_DrawPrimitiveUP,
7411 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7412 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7413 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7414 IWineD3DDeviceImpl_DrawRectPatch,
7415 IWineD3DDeviceImpl_DrawTriPatch,
7416 IWineD3DDeviceImpl_DeletePatch,
7417 IWineD3DDeviceImpl_ColorFill,
7418 IWineD3DDeviceImpl_UpdateTexture,
7419 IWineD3DDeviceImpl_UpdateSurface,
7420 IWineD3DDeviceImpl_GetFrontBufferData,
7421 /*** object tracking ***/
7422 IWineD3DDeviceImpl_ResourceReleased,
7423 IWineD3DDeviceImpl_EnumResources
7427 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7428 WINED3DRS_ALPHABLENDENABLE ,
7429 WINED3DRS_ALPHAFUNC ,
7430 WINED3DRS_ALPHAREF ,
7431 WINED3DRS_ALPHATESTENABLE ,
7433 WINED3DRS_COLORWRITEENABLE ,
7434 WINED3DRS_DESTBLEND ,
7435 WINED3DRS_DITHERENABLE ,
7436 WINED3DRS_FILLMODE ,
7437 WINED3DRS_FOGDENSITY ,
7439 WINED3DRS_FOGSTART ,
7440 WINED3DRS_LASTPIXEL ,
7441 WINED3DRS_SHADEMODE ,
7442 WINED3DRS_SRCBLEND ,
7443 WINED3DRS_STENCILENABLE ,
7444 WINED3DRS_STENCILFAIL ,
7445 WINED3DRS_STENCILFUNC ,
7446 WINED3DRS_STENCILMASK ,
7447 WINED3DRS_STENCILPASS ,
7448 WINED3DRS_STENCILREF ,
7449 WINED3DRS_STENCILWRITEMASK ,
7450 WINED3DRS_STENCILZFAIL ,
7451 WINED3DRS_TEXTUREFACTOR ,
7462 WINED3DRS_ZWRITEENABLE
7465 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7466 WINED3DTSS_ADDRESSW ,
7467 WINED3DTSS_ALPHAARG0 ,
7468 WINED3DTSS_ALPHAARG1 ,
7469 WINED3DTSS_ALPHAARG2 ,
7470 WINED3DTSS_ALPHAOP ,
7471 WINED3DTSS_BUMPENVLOFFSET ,
7472 WINED3DTSS_BUMPENVLSCALE ,
7473 WINED3DTSS_BUMPENVMAT00 ,
7474 WINED3DTSS_BUMPENVMAT01 ,
7475 WINED3DTSS_BUMPENVMAT10 ,
7476 WINED3DTSS_BUMPENVMAT11 ,
7477 WINED3DTSS_COLORARG0 ,
7478 WINED3DTSS_COLORARG1 ,
7479 WINED3DTSS_COLORARG2 ,
7480 WINED3DTSS_COLOROP ,
7481 WINED3DTSS_RESULTARG ,
7482 WINED3DTSS_TEXCOORDINDEX ,
7483 WINED3DTSS_TEXTURETRANSFORMFLAGS
7486 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7487 WINED3DSAMP_ADDRESSU ,
7488 WINED3DSAMP_ADDRESSV ,
7489 WINED3DSAMP_ADDRESSW ,
7490 WINED3DSAMP_BORDERCOLOR ,
7491 WINED3DSAMP_MAGFILTER ,
7492 WINED3DSAMP_MINFILTER ,
7493 WINED3DSAMP_MIPFILTER ,
7494 WINED3DSAMP_MIPMAPLODBIAS ,
7495 WINED3DSAMP_MAXMIPLEVEL ,
7496 WINED3DSAMP_MAXANISOTROPY ,
7497 WINED3DSAMP_SRGBTEXTURE ,
7498 WINED3DSAMP_ELEMENTINDEX
7501 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7503 WINED3DRS_AMBIENTMATERIALSOURCE ,
7504 WINED3DRS_CLIPPING ,
7505 WINED3DRS_CLIPPLANEENABLE ,
7506 WINED3DRS_COLORVERTEX ,
7507 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7508 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7509 WINED3DRS_FOGDENSITY ,
7511 WINED3DRS_FOGSTART ,
7512 WINED3DRS_FOGTABLEMODE ,
7513 WINED3DRS_FOGVERTEXMODE ,
7514 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7515 WINED3DRS_LIGHTING ,
7516 WINED3DRS_LOCALVIEWER ,
7517 WINED3DRS_MULTISAMPLEANTIALIAS ,
7518 WINED3DRS_MULTISAMPLEMASK ,
7519 WINED3DRS_NORMALIZENORMALS ,
7520 WINED3DRS_PATCHEDGESTYLE ,
7521 WINED3DRS_POINTSCALE_A ,
7522 WINED3DRS_POINTSCALE_B ,
7523 WINED3DRS_POINTSCALE_C ,
7524 WINED3DRS_POINTSCALEENABLE ,
7525 WINED3DRS_POINTSIZE ,
7526 WINED3DRS_POINTSIZE_MAX ,
7527 WINED3DRS_POINTSIZE_MIN ,
7528 WINED3DRS_POINTSPRITEENABLE ,
7529 WINED3DRS_RANGEFOGENABLE ,
7530 WINED3DRS_SPECULARMATERIALSOURCE ,
7531 WINED3DRS_TWEENFACTOR ,
7532 WINED3DRS_VERTEXBLEND ,
7533 WINED3DRS_CULLMODE ,
7537 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7538 WINED3DTSS_TEXCOORDINDEX ,
7539 WINED3DTSS_TEXTURETRANSFORMFLAGS
7542 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7543 WINED3DSAMP_DMAPOFFSET
7546 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7547 DWORD rep = StateTable[state].representative;
7551 WineD3DContext *context;
7554 for(i = 0; i < This->numContexts; i++) {
7555 context = This->contexts[i];
7556 if(isStateDirty(context, rep)) continue;
7558 context->dirtyArray[context->numDirtyEntries++] = rep;
7561 context->isStateDirty[idx] |= (1 << shift);
7565 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7566 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7567 /* The drawable size of a pbuffer render target is the current pbuffer size
7569 *width = dev->pbufferWidth;
7570 *height = dev->pbufferHeight;
7573 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7574 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7576 *width = This->pow2Width;
7577 *height = This->pow2Height;
7580 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7581 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7582 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7583 * current context's drawable, which is the size of the back buffer of the swapchain
7584 * the active context belongs to. The back buffer of the swapchain is stored as the
7585 * surface the context belongs to.
7587 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7588 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;