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 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't useable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 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);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
264 object->Flags |= VBFLAG_CREATEVBO;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
586 /* ************************************
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 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.
595 ******************************** */
597 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) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 *******************************/
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
687 case WINED3DPOOL_SCRATCH:
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
728 /* Check if a 3D adapter is available when creating gl surfaces */
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
738 object->lpVtbl = &IWineGDISurface_Vtbl;
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
772 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
773 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
774 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
776 /* TODO: It should only be possible to create textures for formats
777 that are reported as supported */
778 if (WINED3DFMT_UNKNOWN >= Format) {
779 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
780 return WINED3DERR_INVALIDCALL;
783 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
784 D3DINITIALIZEBASETEXTURE(object->baseTexture);
785 object->width = Width;
786 object->height = Height;
788 /** Non-power2 support **/
789 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
793 /* Find the nearest pow2 match */
794 pow2Width = pow2Height = 1;
795 while (pow2Width < Width) pow2Width <<= 1;
796 while (pow2Height < Height) pow2Height <<= 1;
798 if(pow2Width != Width || pow2Height != Height) {
800 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
801 HeapFree(GetProcessHeap(), 0, object);
803 return WINED3DERR_INVALIDCALL;
810 /** FIXME: add support for real non-power-two if it's provided by the video card **/
811 /* Precalculated scaling for 'faked' non power of two texture coords.
812 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
813 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
814 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
816 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
817 (Width != pow2Width || Height != pow2Height) &&
818 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
820 object->baseTexture.pow2Matrix[0] = (float)Width;
821 object->baseTexture.pow2Matrix[5] = (float)Height;
822 object->baseTexture.pow2Matrix[10] = 1.0;
823 object->baseTexture.pow2Matrix[15] = 1.0;
824 object->target = GL_TEXTURE_RECTANGLE_ARB;
826 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
827 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
828 object->baseTexture.pow2Matrix[10] = 1.0;
829 object->baseTexture.pow2Matrix[15] = 1.0;
830 object->target = GL_TEXTURE_2D;
832 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
834 /* Calculate levels for mip mapping */
835 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
836 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
837 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
838 return WINED3DERR_INVALIDCALL;
841 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
842 return WINED3DERR_INVALIDCALL;
844 object->baseTexture.levels = 1;
845 } else if (Levels == 0) {
846 TRACE("calculating levels %d\n", object->baseTexture.levels);
847 object->baseTexture.levels++;
850 while (tmpW > 1 || tmpH > 1) {
851 tmpW = max(1, tmpW >> 1);
852 tmpH = max(1, tmpH >> 1);
853 object->baseTexture.levels++;
855 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
858 /* Generate all the surfaces */
861 for (i = 0; i < object->baseTexture.levels; i++)
863 /* use the callback to create the texture surface */
864 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
865 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
866 FIXME("Failed to create surface %p\n", object);
868 object->surfaces[i] = NULL;
869 IWineD3DTexture_Release((IWineD3DTexture *)object);
875 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
876 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
877 /* calculate the next mipmap level */
878 tmpW = max(1, tmpW >> 1);
879 tmpH = max(1, tmpH >> 1);
881 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
883 TRACE("(%p) : Created texture %p\n", This, object);
887 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
888 UINT Width, UINT Height, UINT Depth,
889 UINT Levels, DWORD Usage,
890 WINED3DFORMAT Format, WINED3DPOOL Pool,
891 IWineD3DVolumeTexture **ppVolumeTexture,
892 HANDLE *pSharedHandle, IUnknown *parent,
893 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
896 IWineD3DVolumeTextureImpl *object;
901 const GlPixelFormatDesc *glDesc;
903 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
905 /* TODO: It should only be possible to create textures for formats
906 that are reported as supported */
907 if (WINED3DFMT_UNKNOWN >= Format) {
908 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
909 return WINED3DERR_INVALIDCALL;
911 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
912 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
913 return WINED3DERR_INVALIDCALL;
916 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
917 D3DINITIALIZEBASETEXTURE(object->baseTexture);
919 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
920 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
922 object->width = Width;
923 object->height = Height;
924 object->depth = Depth;
926 /* Is NP2 support for volumes needed? */
927 object->baseTexture.pow2Matrix[ 0] = 1.0;
928 object->baseTexture.pow2Matrix[ 5] = 1.0;
929 object->baseTexture.pow2Matrix[10] = 1.0;
930 object->baseTexture.pow2Matrix[15] = 1.0;
932 /* Calculate levels for mip mapping */
933 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
934 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
935 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
936 return WINED3DERR_INVALIDCALL;
939 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
940 return WINED3DERR_INVALIDCALL;
943 } else if (Levels == 0) {
944 object->baseTexture.levels++;
948 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
949 tmpW = max(1, tmpW >> 1);
950 tmpH = max(1, tmpH >> 1);
951 tmpD = max(1, tmpD >> 1);
952 object->baseTexture.levels++;
954 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
957 /* Generate all the surfaces */
962 for (i = 0; i < object->baseTexture.levels; i++)
965 /* Create the volume */
966 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
967 &object->volumes[i], pSharedHandle);
970 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
971 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
972 *ppVolumeTexture = NULL;
976 /* Set its container to this object */
977 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
979 /* calculate the next mipmap level */
980 tmpW = max(1, tmpW >> 1);
981 tmpH = max(1, tmpH >> 1);
982 tmpD = max(1, tmpD >> 1);
984 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
986 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
987 TRACE("(%p) : Created volume texture %p\n", This, object);
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
992 UINT Width, UINT Height, UINT Depth,
994 WINED3DFORMAT Format, WINED3DPOOL Pool,
995 IWineD3DVolume** ppVolume,
996 HANDLE* pSharedHandle, IUnknown *parent) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1002 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1003 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1009 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1010 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.Depth = Depth;
1015 object->bytesPerPixel = formatDesc->bpp;
1017 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1018 object->lockable = TRUE;
1019 object->locked = FALSE;
1020 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1021 object->dirty = TRUE;
1023 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1027 UINT Levels, DWORD Usage,
1028 WINED3DFORMAT Format, WINED3DPOOL Pool,
1029 IWineD3DCubeTexture **ppCubeTexture,
1030 HANDLE *pSharedHandle, IUnknown *parent,
1031 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1038 unsigned int pow2EdgeLength = EdgeLength;
1039 const GlPixelFormatDesc *glDesc;
1040 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1042 /* TODO: It should only be possible to create textures for formats
1043 that are reported as supported */
1044 if (WINED3DFMT_UNKNOWN >= Format) {
1045 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1046 return WINED3DERR_INVALIDCALL;
1049 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1050 WARN("(%p) : Tried to create not supported cube texture\n", This);
1051 return WINED3DERR_INVALIDCALL;
1054 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1055 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1057 TRACE("(%p) Create Cube Texture\n", This);
1059 /** Non-power2 support **/
1061 /* Find the nearest pow2 match */
1063 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1065 object->edgeLength = EdgeLength;
1066 /* TODO: support for native non-power 2 */
1067 /* Precalculated scaling for 'faked' non power of two texture coords */
1068 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1069 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1070 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1071 object->baseTexture.pow2Matrix[15] = 1.0;
1073 /* Calculate levels for mip mapping */
1074 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1075 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1076 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1077 HeapFree(GetProcessHeap(), 0, object);
1078 *ppCubeTexture = NULL;
1080 return WINED3DERR_INVALIDCALL;
1083 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1084 HeapFree(GetProcessHeap(), 0, object);
1085 *ppCubeTexture = NULL;
1087 return WINED3DERR_INVALIDCALL;
1090 } else if (Levels == 0) {
1091 object->baseTexture.levels++;
1094 tmpW = max(1, tmpW >> 1);
1095 object->baseTexture.levels++;
1097 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1100 /* Generate all the surfaces */
1102 for (i = 0; i < object->baseTexture.levels; i++) {
1104 /* Create the 6 faces */
1105 for (j = 0; j < 6; j++) {
1107 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1108 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1110 if(hr!= WINED3D_OK) {
1114 for (l = 0; l < j; l++) {
1115 IWineD3DSurface_Release(object->surfaces[l][i]);
1117 for (k = 0; k < i; k++) {
1118 for (l = 0; l < 6; l++) {
1119 IWineD3DSurface_Release(object->surfaces[l][k]);
1123 FIXME("(%p) Failed to create surface\n",object);
1124 HeapFree(GetProcessHeap(),0,object);
1125 *ppCubeTexture = NULL;
1128 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1129 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1131 tmpW = max(1, tmpW >> 1);
1133 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1135 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1136 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1140 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1142 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1143 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1144 const IWineD3DQueryVtbl *vtable;
1146 /* Just a check to see if we support this type of query */
1148 case WINED3DQUERYTYPE_OCCLUSION:
1149 TRACE("(%p) occlusion query\n", This);
1150 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1153 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1155 vtable = &IWineD3DOcclusionQuery_Vtbl;
1158 case WINED3DQUERYTYPE_EVENT:
1159 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1160 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1161 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1163 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1165 vtable = &IWineD3DEventQuery_Vtbl;
1169 case WINED3DQUERYTYPE_VCACHE:
1170 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1171 case WINED3DQUERYTYPE_VERTEXSTATS:
1172 case WINED3DQUERYTYPE_TIMESTAMP:
1173 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1174 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1175 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1176 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1177 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1178 case WINED3DQUERYTYPE_PIXELTIMINGS:
1179 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1180 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1182 /* Use the base Query vtable until we have a special one for each query */
1183 vtable = &IWineD3DQuery_Vtbl;
1184 FIXME("(%p) Unhandled query type %d\n", This, Type);
1186 if(NULL == ppQuery || hr != WINED3D_OK) {
1190 D3DCREATEOBJECTINSTANCE(object, Query)
1191 object->lpVtbl = vtable;
1192 object->type = Type;
1193 object->state = QUERY_CREATED;
1194 /* allocated the 'extended' data based on the type of query requested */
1196 case WINED3DQUERYTYPE_OCCLUSION:
1197 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1198 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1200 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1201 TRACE("(%p) Allocating data for an occlusion query\n", This);
1202 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1205 case WINED3DQUERYTYPE_EVENT:
1206 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1207 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1209 if(GL_SUPPORT(APPLE_FENCE)) {
1210 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1211 checkGLcall("glGenFencesAPPLE");
1212 } else if(GL_SUPPORT(NV_FENCE)) {
1213 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1214 checkGLcall("glGenFencesNV");
1218 case WINED3DQUERYTYPE_VCACHE:
1219 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1220 case WINED3DQUERYTYPE_VERTEXSTATS:
1221 case WINED3DQUERYTYPE_TIMESTAMP:
1222 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1223 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1224 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1225 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1226 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1227 case WINED3DQUERYTYPE_PIXELTIMINGS:
1228 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1229 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1231 object->extendedData = 0;
1232 FIXME("(%p) Unhandled query type %d\n",This , Type);
1234 TRACE("(%p) : Created Query %p\n", This, object);
1238 /*****************************************************************************
1239 * IWineD3DDeviceImpl_SetupFullscreenWindow
1241 * Helper function that modifies a HWND's Style and ExStyle for proper
1245 * iface: Pointer to the IWineD3DDevice interface
1246 * window: Window to setup
1248 *****************************************************************************/
1249 static LONG fullscreen_style(LONG orig_style) {
1250 LONG style = orig_style;
1251 style &= ~WS_CAPTION;
1252 style &= ~WS_THICKFRAME;
1254 /* Make sure the window is managed, otherwise we won't get keyboard input */
1255 style |= WS_POPUP | WS_SYSMENU;
1260 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1261 LONG exStyle = orig_exStyle;
1263 /* Filter out window decorations */
1264 exStyle &= ~WS_EX_WINDOWEDGE;
1265 exStyle &= ~WS_EX_CLIENTEDGE;
1270 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1273 LONG style, exStyle;
1274 /* Don't do anything if an original style is stored.
1275 * That shouldn't happen
1277 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1278 if (This->style || This->exStyle) {
1279 ERR("(%p): Want to change the window parameters of HWND %p, but "
1280 "another style is stored for restoration afterwards\n", This, window);
1283 /* Get the parameters and save them */
1284 style = GetWindowLongW(window, GWL_STYLE);
1285 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1286 This->style = style;
1287 This->exStyle = exStyle;
1289 style = fullscreen_style(style);
1290 exStyle = fullscreen_exStyle(exStyle);
1292 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1293 This->style, This->exStyle, style, exStyle);
1295 SetWindowLongW(window, GWL_STYLE, style);
1296 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1298 /* Inform the window about the update. */
1299 SetWindowPos(window, HWND_TOP, 0, 0,
1300 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1301 ShowWindow(window, SW_NORMAL);
1304 /*****************************************************************************
1305 * IWineD3DDeviceImpl_RestoreWindow
1307 * Helper function that restores a windows' properties when taking it out
1308 * of fullscreen mode
1311 * iface: Pointer to the IWineD3DDevice interface
1312 * window: Window to setup
1314 *****************************************************************************/
1315 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1317 LONG style, exStyle;
1319 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1320 * switch, do nothing
1322 if (!This->style && !This->exStyle) return;
1324 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1325 This, window, This->style, This->exStyle);
1327 style = GetWindowLongW(window, GWL_STYLE);
1328 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1330 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1331 * Some applications change it before calling Reset() when switching between windowed and
1332 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1334 if(style == fullscreen_style(This->style) &&
1335 exStyle == fullscreen_style(This->exStyle)) {
1336 SetWindowLongW(window, GWL_STYLE, This->style);
1337 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1340 /* Delete the old values */
1344 /* Inform the window about the update */
1345 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1346 0, 0, 0, 0, /* Pos, Size, ignored */
1347 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1350 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1351 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1353 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1354 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1355 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1358 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1359 HRESULT hr = WINED3D_OK;
1360 IUnknown *bufferParent;
1361 BOOL displaymode_set = FALSE;
1362 WINED3DDISPLAYMODE Mode;
1363 const StaticPixelFormatDesc *formatDesc;
1365 TRACE("(%p) : Created Additional Swap Chain\n", This);
1367 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1368 * does a device hold a reference to a swap chain giving them a lifetime of the device
1369 * or does the swap chain notify the device of its destruction.
1370 *******************************/
1372 /* Check the params */
1373 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1374 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1375 return WINED3DERR_INVALIDCALL;
1376 } else if (pPresentationParameters->BackBufferCount > 1) {
1377 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");
1380 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1382 /*********************
1383 * Lookup the window Handle and the relating X window handle
1384 ********************/
1386 /* Setup hwnd we are using, plus which display this equates to */
1387 object->win_handle = pPresentationParameters->hDeviceWindow;
1388 if (!object->win_handle) {
1389 object->win_handle = This->createParms.hFocusWindow;
1391 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1393 hDc = GetDC(object->win_handle);
1394 TRACE("Using hDc %p\n", hDc);
1397 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1398 return WINED3DERR_NOTAVAILABLE;
1401 /* Get info on the current display setup */
1402 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1403 object->orig_width = Mode.Width;
1404 object->orig_height = Mode.Height;
1405 object->orig_fmt = Mode.Format;
1406 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1408 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1409 * then the corresponding dimension of the client area of the hDeviceWindow
1410 * (or the focus window, if hDeviceWindow is NULL) is taken.
1411 **********************/
1413 if (pPresentationParameters->Windowed &&
1414 ((pPresentationParameters->BackBufferWidth == 0) ||
1415 (pPresentationParameters->BackBufferHeight == 0) ||
1416 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1419 GetClientRect(object->win_handle, &Rect);
1421 if (pPresentationParameters->BackBufferWidth == 0) {
1422 pPresentationParameters->BackBufferWidth = Rect.right;
1423 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1425 if (pPresentationParameters->BackBufferHeight == 0) {
1426 pPresentationParameters->BackBufferHeight = Rect.bottom;
1427 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1429 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1430 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1431 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1435 /* Put the correct figures in the presentation parameters */
1436 TRACE("Copying across presentation parameters\n");
1437 object->presentParms = *pPresentationParameters;
1439 TRACE("calling rendertarget CB\n");
1440 hr = D3DCB_CreateRenderTarget(This->parent,
1442 object->presentParms.BackBufferWidth,
1443 object->presentParms.BackBufferHeight,
1444 object->presentParms.BackBufferFormat,
1445 object->presentParms.MultiSampleType,
1446 object->presentParms.MultiSampleQuality,
1447 TRUE /* Lockable */,
1448 &object->frontBuffer,
1449 NULL /* pShared (always null)*/);
1450 if (object->frontBuffer != NULL) {
1451 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1452 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1454 ERR("Failed to create the front buffer\n");
1458 /*********************
1459 * Windowed / Fullscreen
1460 *******************/
1463 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1464 * so we should really check to see if there is a fullscreen swapchain already
1465 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1466 **************************************/
1468 if (!pPresentationParameters->Windowed) {
1469 WINED3DDISPLAYMODE mode;
1472 /* Change the display settings */
1473 mode.Width = pPresentationParameters->BackBufferWidth;
1474 mode.Height = pPresentationParameters->BackBufferHeight;
1475 mode.Format = pPresentationParameters->BackBufferFormat;
1476 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1478 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1479 displaymode_set = TRUE;
1480 IWineD3DDevice_SetFullscreen(iface, TRUE);
1484 * Create an opengl context for the display visual
1485 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1486 * use different properties after that point in time. FIXME: How to handle when requested format
1487 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1488 * it chooses is identical to the one already being used!
1489 **********************************/
1490 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1492 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1493 if(!object->context)
1494 return E_OUTOFMEMORY;
1495 object->num_contexts = 1;
1497 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1498 if (!object->context[0]) {
1499 ERR("Failed to create a new context\n");
1500 hr = WINED3DERR_NOTAVAILABLE;
1503 TRACE("Context created (HWND=%p, glContext=%p)\n",
1504 object->win_handle, object->context[0]->glCtx);
1507 /*********************
1508 * Create the back, front and stencil buffers
1509 *******************/
1510 if(object->presentParms.BackBufferCount > 0) {
1513 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1514 if(!object->backBuffer) {
1515 ERR("Out of memory\n");
1520 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1521 TRACE("calling rendertarget CB\n");
1522 hr = D3DCB_CreateRenderTarget(This->parent,
1524 object->presentParms.BackBufferWidth,
1525 object->presentParms.BackBufferHeight,
1526 object->presentParms.BackBufferFormat,
1527 object->presentParms.MultiSampleType,
1528 object->presentParms.MultiSampleQuality,
1529 TRUE /* Lockable */,
1530 &object->backBuffer[i],
1531 NULL /* pShared (always null)*/);
1532 if(hr == WINED3D_OK && object->backBuffer[i]) {
1533 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1535 ERR("Cannot create new back buffer\n");
1539 glDrawBuffer(GL_BACK);
1540 checkGLcall("glDrawBuffer(GL_BACK)");
1544 object->backBuffer = NULL;
1546 /* Single buffering - draw to front buffer */
1548 glDrawBuffer(GL_FRONT);
1549 checkGLcall("glDrawBuffer(GL_FRONT)");
1553 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1554 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1555 TRACE("Creating depth stencil buffer\n");
1556 if (This->auto_depth_stencil_buffer == NULL ) {
1557 hr = D3DCB_CreateDepthStencil(This->parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.AutoDepthStencilFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 FALSE /* FIXME: Discard */,
1565 &This->auto_depth_stencil_buffer,
1566 NULL /* pShared (always null)*/ );
1567 if (This->auto_depth_stencil_buffer != NULL)
1568 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1571 /** TODO: A check on width, height and multisample types
1572 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1573 ****************************/
1574 object->wantsDepthStencilBuffer = TRUE;
1576 object->wantsDepthStencilBuffer = FALSE;
1579 TRACE("Created swapchain %p\n", object);
1580 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1584 if (displaymode_set) {
1588 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1591 /* Change the display settings */
1592 memset(&devmode, 0, sizeof(devmode));
1593 devmode.dmSize = sizeof(devmode);
1594 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1595 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1596 devmode.dmPelsWidth = object->orig_width;
1597 devmode.dmPelsHeight = object->orig_height;
1598 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1601 if (object->backBuffer) {
1603 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1604 if(object->backBuffer[i]) {
1605 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1606 IUnknown_Release(bufferParent); /* once for the get parent */
1607 if (IUnknown_Release(bufferParent) > 0) {
1608 FIXME("(%p) Something's still holding the back buffer\n",This);
1612 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1613 object->backBuffer = NULL;
1615 if(object->context[0])
1616 DestroyContext(This, object->context[0]);
1617 if(object->frontBuffer) {
1618 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1619 IUnknown_Release(bufferParent); /* once for the get parent */
1620 if (IUnknown_Release(bufferParent) > 0) {
1621 FIXME("(%p) Something's still holding the front buffer\n",This);
1624 HeapFree(GetProcessHeap(), 0, object);
1628 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1629 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1631 TRACE("(%p)\n", This);
1633 return This->NumberOfSwapChains;
1636 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1638 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1640 if(iSwapChain < This->NumberOfSwapChains) {
1641 *pSwapChain = This->swapchains[iSwapChain];
1642 IWineD3DSwapChain_AddRef(*pSwapChain);
1643 TRACE("(%p) returning %p\n", This, *pSwapChain);
1646 TRACE("Swapchain out of range\n");
1648 return WINED3DERR_INVALIDCALL;
1653 * Vertex Declaration
1655 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1656 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1658 IWineD3DVertexDeclarationImpl *object = NULL;
1659 HRESULT hr = WINED3D_OK;
1661 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1662 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1664 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1666 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1668 *ppVertexDeclaration = NULL;
1669 HeapFree(GetProcessHeap(), 0, object);
1675 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1676 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1678 unsigned int idx, idx2;
1679 unsigned int offset;
1680 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1681 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1682 BOOL has_blend_idx = has_blend &&
1683 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1684 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1685 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1686 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1687 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1688 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1689 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1691 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1692 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1694 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1695 WINED3DVERTEXELEMENT *elements = NULL;
1698 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1699 if (has_blend_idx) num_blends--;
1701 /* Compute declaration size */
1702 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1703 has_psize + has_diffuse + has_specular + num_textures + 1;
1705 /* convert the declaration */
1706 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1710 elements[size-1] = end_element;
1713 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1714 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1715 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1718 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1719 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1721 elements[idx].UsageIndex = 0;
1724 if (has_blend && (num_blends > 0)) {
1725 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1726 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1728 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1729 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1730 elements[idx].UsageIndex = 0;
1733 if (has_blend_idx) {
1734 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1735 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1736 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1737 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1738 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1740 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1741 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1742 elements[idx].UsageIndex = 0;
1746 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1747 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1748 elements[idx].UsageIndex = 0;
1752 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1753 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1754 elements[idx].UsageIndex = 0;
1758 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1759 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1760 elements[idx].UsageIndex = 0;
1764 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1765 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1766 elements[idx].UsageIndex = 1;
1769 for (idx2 = 0; idx2 < num_textures; idx2++) {
1770 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1771 switch (numcoords) {
1772 case WINED3DFVF_TEXTUREFORMAT1:
1773 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1775 case WINED3DFVF_TEXTUREFORMAT2:
1776 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1778 case WINED3DFVF_TEXTUREFORMAT3:
1779 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1781 case WINED3DFVF_TEXTUREFORMAT4:
1782 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1785 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1786 elements[idx].UsageIndex = idx2;
1790 /* Now compute offsets, and initialize the rest of the fields */
1791 for (idx = 0, offset = 0; idx < size-1; idx++) {
1792 elements[idx].Stream = 0;
1793 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1794 elements[idx].Offset = offset;
1795 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1798 *ppVertexElements = elements;
1802 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1803 WINED3DVERTEXELEMENT* elements = NULL;
1804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1808 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1809 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1811 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1812 HeapFree(GetProcessHeap(), 0, elements);
1813 if (hr != S_OK) return hr;
1818 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1820 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1821 HRESULT hr = WINED3D_OK;
1822 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1823 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1825 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1827 if (vertex_declaration) {
1828 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1831 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1833 if (WINED3D_OK != hr) {
1834 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1835 IWineD3DVertexShader_Release(*ppVertexShader);
1836 return WINED3DERR_INVALIDCALL;
1838 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1843 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1845 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1846 HRESULT hr = WINED3D_OK;
1848 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1849 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1850 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1851 if (WINED3D_OK == hr) {
1852 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1853 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1855 WARN("(%p) : Failed to create pixel shader\n", This);
1861 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1863 IWineD3DPaletteImpl *object;
1865 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1867 /* Create the new object */
1868 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1870 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1871 return E_OUTOFMEMORY;
1874 object->lpVtbl = &IWineD3DPalette_Vtbl;
1876 object->Flags = Flags;
1877 object->parent = Parent;
1878 object->wineD3DDevice = This;
1879 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1881 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1884 HeapFree( GetProcessHeap(), 0, object);
1885 return E_OUTOFMEMORY;
1888 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1890 IWineD3DPalette_Release((IWineD3DPalette *) object);
1894 *Palette = (IWineD3DPalette *) object;
1899 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1903 HDC dcb = NULL, dcs = NULL;
1904 WINEDDCOLORKEY colorkey;
1906 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1909 GetObjectA(hbm, sizeof(BITMAP), &bm);
1910 dcb = CreateCompatibleDC(NULL);
1912 SelectObject(dcb, hbm);
1916 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1917 * couldn't be loaded
1919 memset(&bm, 0, sizeof(bm));
1924 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1925 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1926 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1928 ERR("Wine logo requested, but failed to create surface\n");
1933 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1934 if(FAILED(hr)) goto out;
1935 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1936 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1938 colorkey.dwColorSpaceLowValue = 0;
1939 colorkey.dwColorSpaceHighValue = 0;
1940 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1942 /* Fill the surface with a white color to show that wined3d is there */
1943 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1956 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1958 /* Under DirectX you can have texture stage operations even if no texture is
1959 bound, whereas opengl will only do texture operations when a valid texture is
1960 bound. We emulate this by creating dummy textures and binding them to each
1961 texture stage, but disable all stages by default. Hence if a stage is enabled
1962 then the default texture will kick in until replaced by a SetTexture call */
1965 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1966 /* The dummy texture does not have client storage backing */
1967 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1968 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1970 for (i = 0; i < GL_LIMITS(textures); i++) {
1971 GLubyte white = 255;
1973 /* Make appropriate texture active */
1974 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1975 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1976 checkGLcall("glActiveTextureARB");
1978 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1981 /* Generate an opengl texture name */
1982 glGenTextures(1, &This->dummyTextureName[i]);
1983 checkGLcall("glGenTextures");
1984 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1986 /* Generate a dummy 2d texture (not using 1d because they cause many
1987 * DRI drivers fall back to sw) */
1988 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
1989 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
1990 checkGLcall("glBindTexture");
1992 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
1993 checkGLcall("glTexImage2D");
1995 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1996 /* Reenable because if supported it is enabled by default */
1997 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
1998 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2004 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2006 IWineD3DSwapChainImpl *swapchain = NULL;
2010 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2011 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2013 /* TODO: Test if OpenGL is compiled in and loaded */
2015 TRACE("(%p) : Creating stateblock\n", This);
2016 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2017 hr = IWineD3DDevice_CreateStateBlock(iface,
2019 (IWineD3DStateBlock **)&This->stateBlock,
2021 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2022 WARN("Failed to create stateblock\n");
2025 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2026 This->updateStateBlock = This->stateBlock;
2027 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2029 hr = allocate_shader_constants(This->updateStateBlock);
2030 if (WINED3D_OK != hr) {
2034 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2035 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2036 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2038 /* Initialize the texture unit mapping to a 1:1 mapping */
2039 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2040 if (state < GL_LIMITS(fragment_samplers)) {
2041 This->texUnitMap[state] = state;
2042 This->rev_tex_unit_map[state] = state;
2044 This->texUnitMap[state] = -1;
2045 This->rev_tex_unit_map[state] = -1;
2049 /* Setup the implicit swapchain */
2050 TRACE("Creating implicit swapchain\n");
2051 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2052 if (FAILED(hr) || !swapchain) {
2053 WARN("Failed to create implicit swapchain\n");
2057 This->NumberOfSwapChains = 1;
2058 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2059 if(!This->swapchains) {
2060 ERR("Out of memory!\n");
2063 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2065 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2066 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2067 This->render_targets[0] = swapchain->backBuffer[0];
2068 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2071 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2072 This->render_targets[0] = swapchain->frontBuffer;
2073 This->lastActiveRenderTarget = swapchain->frontBuffer;
2075 IWineD3DSurface_AddRef(This->render_targets[0]);
2076 This->activeContext = swapchain->context[0];
2077 This->lastThread = GetCurrentThreadId();
2079 /* Depth Stencil support */
2080 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2081 if (NULL != This->stencilBufferTarget) {
2082 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2085 hr = This->shader_backend->shader_alloc_private(iface);
2087 TRACE("Shader private data couldn't be allocated\n");
2091 /* Set up some starting GL setup */
2094 /* Setup all the devices defaults */
2095 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2096 create_dummy_textures(This);
2098 IWineD3DImpl_CheckGraphicsMemory();
2101 { /* Set a default viewport */
2105 vp.Width = pPresentationParameters->BackBufferWidth;
2106 vp.Height = pPresentationParameters->BackBufferHeight;
2109 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2112 /* Initialize the current view state */
2113 This->view_ident = 1;
2114 This->contexts[0]->last_was_rhw = 0;
2115 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2116 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2118 switch(wined3d_settings.offscreen_rendering_mode) {
2121 This->offscreenBuffer = GL_BACK;
2124 case ORM_BACKBUFFER:
2126 if(GL_LIMITS(aux_buffers) > 0) {
2127 TRACE("Using auxilliary buffer for offscreen rendering\n");
2128 This->offscreenBuffer = GL_AUX0;
2130 TRACE("Using back buffer for offscreen rendering\n");
2131 This->offscreenBuffer = GL_BACK;
2136 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2139 /* Clear the screen */
2140 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2141 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2144 This->d3d_initialized = TRUE;
2146 if(wined3d_settings.logo) {
2147 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2149 This->highest_dirty_ps_const = 0;
2150 This->highest_dirty_vs_const = 0;
2154 This->shader_backend->shader_free_private(iface);
2155 HeapFree(GetProcessHeap(), 0, This->render_targets);
2156 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2157 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2158 HeapFree(GetProcessHeap(), 0, This->swapchains);
2159 This->NumberOfSwapChains = 0;
2161 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2163 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2164 if(This->stateBlock) {
2165 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2166 This->stateBlock = NULL;
2171 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2175 TRACE("(%p)\n", This);
2177 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2179 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2180 * it was created. Thus make sure a context is active for the glDelete* calls
2182 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2184 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2186 TRACE("Deleting high order patches\n");
2187 for(i = 0; i < PATCHMAP_SIZE; i++) {
2188 struct list *e1, *e2;
2189 struct WineD3DRectPatch *patch;
2190 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2191 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2192 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2196 /* Delete the palette conversion shader if it is around */
2197 if(This->paletteConversionShader) {
2198 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2199 This->paletteConversionShader = 0;
2202 /* Delete the pbuffer context if there is any */
2203 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2205 /* Delete the mouse cursor texture */
2206 if(This->cursorTexture) {
2208 glDeleteTextures(1, &This->cursorTexture);
2210 This->cursorTexture = 0;
2213 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2214 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2216 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2217 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2220 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2221 * private data, it might contain opengl pointers
2223 This->shader_backend->shader_destroy_depth_blt(iface);
2224 This->shader_backend->shader_free_private(iface);
2226 /* Release the update stateblock */
2227 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2228 if(This->updateStateBlock != This->stateBlock)
2229 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2231 This->updateStateBlock = NULL;
2233 { /* because were not doing proper internal refcounts releasing the primary state block
2234 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2235 to set this->stateBlock = NULL; first */
2236 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2237 This->stateBlock = NULL;
2239 /* Release the stateblock */
2240 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2241 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2245 /* Release the buffers (with sanity checks)*/
2246 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2247 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2248 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2249 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2251 This->stencilBufferTarget = NULL;
2253 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2254 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2255 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2257 TRACE("Setting rendertarget to NULL\n");
2258 This->render_targets[0] = NULL;
2260 if (This->auto_depth_stencil_buffer) {
2261 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2262 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2264 This->auto_depth_stencil_buffer = NULL;
2267 for(i=0; i < This->NumberOfSwapChains; i++) {
2268 TRACE("Releasing the implicit swapchain %d\n", i);
2269 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2270 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2274 HeapFree(GetProcessHeap(), 0, This->swapchains);
2275 This->swapchains = NULL;
2276 This->NumberOfSwapChains = 0;
2278 HeapFree(GetProcessHeap(), 0, This->render_targets);
2279 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2280 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2281 This->render_targets = NULL;
2282 This->fbo_color_attachments = NULL;
2283 This->draw_buffers = NULL;
2286 This->d3d_initialized = FALSE;
2290 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2292 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2294 /* Setup the window for fullscreen mode */
2295 if(fullscreen && !This->ddraw_fullscreen) {
2296 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2297 } else if(!fullscreen && This->ddraw_fullscreen) {
2298 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2301 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2302 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2303 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2306 This->ddraw_fullscreen = fullscreen;
2309 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2310 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2311 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2313 * There is no way to deactivate thread safety once it is enabled.
2315 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2318 /*For now just store the flag(needed in case of ddraw) */
2319 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2324 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2328 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2331 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2333 /* Resize the screen even without a window:
2334 * The app could have unset it with SetCooperativeLevel, but not called
2335 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2336 * but we don't have any hwnd
2339 memset(&devmode, 0, sizeof(devmode));
2340 devmode.dmSize = sizeof(devmode);
2341 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2342 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2343 devmode.dmPelsWidth = pMode->Width;
2344 devmode.dmPelsHeight = pMode->Height;
2346 devmode.dmDisplayFrequency = pMode->RefreshRate;
2347 if (pMode->RefreshRate != 0) {
2348 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2351 /* Only change the mode if necessary */
2352 if( (This->ddraw_width == pMode->Width) &&
2353 (This->ddraw_height == pMode->Height) &&
2354 (This->ddraw_format == pMode->Format) &&
2355 (pMode->RefreshRate == 0) ) {
2359 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2360 if (ret != DISP_CHANGE_SUCCESSFUL) {
2361 if(devmode.dmDisplayFrequency != 0) {
2362 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2363 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2364 devmode.dmDisplayFrequency = 0;
2365 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2367 if(ret != DISP_CHANGE_SUCCESSFUL) {
2368 return WINED3DERR_NOTAVAILABLE;
2372 /* Store the new values */
2373 This->ddraw_width = pMode->Width;
2374 This->ddraw_height = pMode->Height;
2375 This->ddraw_format = pMode->Format;
2377 /* Only do this with a window of course, and only if we're fullscreened */
2378 if(This->ddraw_window && This->ddraw_fullscreen)
2379 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2381 /* And finally clip mouse to our screen */
2382 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2383 ClipCursor(&clip_rc);
2388 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2390 *ppD3D= This->wineD3D;
2391 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2392 IWineD3D_AddRef(*ppD3D);
2396 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2399 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2400 (This->adapter->TextureRam/(1024*1024)),
2401 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2402 /* return simulated texture memory left */
2403 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2411 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2414 /* Update the current state block */
2415 This->updateStateBlock->changed.fvf = TRUE;
2417 if(This->updateStateBlock->fvf == fvf) {
2418 TRACE("Application is setting the old fvf over, nothing to do\n");
2422 This->updateStateBlock->fvf = fvf;
2423 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2429 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2431 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2432 *pfvf = This->stateBlock->fvf;
2437 * Get / Set Stream Source
2439 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2441 IWineD3DVertexBuffer *oldSrc;
2443 if (StreamNumber >= MAX_STREAMS) {
2444 WARN("Stream out of range %d\n", StreamNumber);
2445 return WINED3DERR_INVALIDCALL;
2446 } else if(OffsetInBytes & 0x3) {
2447 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2448 return WINED3DERR_INVALIDCALL;
2451 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2452 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2454 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2456 if(oldSrc == pStreamData &&
2457 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2458 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2459 TRACE("Application is setting the old values over, nothing to do\n");
2463 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2465 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2466 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2469 /* Handle recording of state blocks */
2470 if (This->isRecordingState) {
2471 TRACE("Recording... not performing anything\n");
2472 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2473 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2477 /* Need to do a getParent and pass the references up */
2478 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2479 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2480 so for now, just count internally */
2481 if (pStreamData != NULL) {
2482 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2483 InterlockedIncrement(&vbImpl->bindCount);
2484 IWineD3DVertexBuffer_AddRef(pStreamData);
2486 if (oldSrc != NULL) {
2487 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2488 IWineD3DVertexBuffer_Release(oldSrc);
2491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2496 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2499 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2500 This->stateBlock->streamSource[StreamNumber],
2501 This->stateBlock->streamOffset[StreamNumber],
2502 This->stateBlock->streamStride[StreamNumber]);
2504 if (StreamNumber >= MAX_STREAMS) {
2505 WARN("Stream out of range %d\n", StreamNumber);
2506 return WINED3DERR_INVALIDCALL;
2508 *pStream = This->stateBlock->streamSource[StreamNumber];
2509 *pStride = This->stateBlock->streamStride[StreamNumber];
2511 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2514 if (*pStream != NULL) {
2515 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2520 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2522 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2523 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2525 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2526 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2528 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2529 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2531 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2532 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2539 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2543 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2545 TRACE("(%p) : returning %d\n", This, *Divider);
2551 * Get / Set & Multiply Transform
2553 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 /* Most of this routine, comments included copied from ddraw tree initially: */
2557 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2559 /* Handle recording of state blocks */
2560 if (This->isRecordingState) {
2561 TRACE("Recording... not performing anything\n");
2562 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2563 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2568 * If the new matrix is the same as the current one,
2569 * we cut off any further processing. this seems to be a reasonable
2570 * optimization because as was noticed, some apps (warcraft3 for example)
2571 * tend towards setting the same matrix repeatedly for some reason.
2573 * From here on we assume that the new matrix is different, wherever it matters.
2575 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2576 TRACE("The app is setting the same matrix over again\n");
2579 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2583 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2584 where ViewMat = Camera space, WorldMat = world space.
2586 In OpenGL, camera and world space is combined into GL_MODELVIEW
2587 matrix. The Projection matrix stay projection matrix.
2590 /* Capture the times we can just ignore the change for now */
2591 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2592 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2593 /* Handled by the state manager */
2596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2600 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2601 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2603 *pMatrix = This->stateBlock->transforms[State];
2607 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2608 WINED3DMATRIX *mat = NULL;
2611 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2612 * below means it will be recorded in a state block change, but it
2613 * works regardless where it is recorded.
2614 * If this is found to be wrong, change to StateBlock.
2616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2617 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2619 if (State < HIGHEST_TRANSFORMSTATE)
2621 mat = &This->updateStateBlock->transforms[State];
2623 FIXME("Unhandled transform state!!\n");
2626 multiply_matrix(&temp, mat, pMatrix);
2628 /* Apply change via set transform - will reapply to eg. lights this way */
2629 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2635 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2636 you can reference any indexes you want as long as that number max are enabled at any
2637 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2638 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2639 but when recording, just build a chain pretty much of commands to be replayed. */
2641 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2643 PLIGHTINFOEL *object = NULL;
2644 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2648 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2650 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2654 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2658 switch(pLight->Type) {
2659 case WINED3DLIGHT_POINT:
2660 case WINED3DLIGHT_SPOT:
2661 case WINED3DLIGHT_PARALLELPOINT:
2662 case WINED3DLIGHT_GLSPOT:
2663 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2666 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2667 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2668 return WINED3DERR_INVALIDCALL;
2672 case WINED3DLIGHT_DIRECTIONAL:
2673 /* Ignores attenuation */
2677 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2678 return WINED3DERR_INVALIDCALL;
2681 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2682 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2683 if(object->OriginalIndex == Index) break;
2688 TRACE("Adding new light\n");
2689 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2691 ERR("Out of memory error when allocating a light\n");
2692 return E_OUTOFMEMORY;
2694 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2695 object->glIndex = -1;
2696 object->OriginalIndex = Index;
2697 object->changed = TRUE;
2700 /* Initialize the object */
2701 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,
2702 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2703 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2704 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2705 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2706 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2707 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2709 /* Save away the information */
2710 object->OriginalParms = *pLight;
2712 switch (pLight->Type) {
2713 case WINED3DLIGHT_POINT:
2715 object->lightPosn[0] = pLight->Position.x;
2716 object->lightPosn[1] = pLight->Position.y;
2717 object->lightPosn[2] = pLight->Position.z;
2718 object->lightPosn[3] = 1.0f;
2719 object->cutoff = 180.0f;
2723 case WINED3DLIGHT_DIRECTIONAL:
2725 object->lightPosn[0] = -pLight->Direction.x;
2726 object->lightPosn[1] = -pLight->Direction.y;
2727 object->lightPosn[2] = -pLight->Direction.z;
2728 object->lightPosn[3] = 0.0;
2729 object->exponent = 0.0f;
2730 object->cutoff = 180.0f;
2733 case WINED3DLIGHT_SPOT:
2735 object->lightPosn[0] = pLight->Position.x;
2736 object->lightPosn[1] = pLight->Position.y;
2737 object->lightPosn[2] = pLight->Position.z;
2738 object->lightPosn[3] = 1.0;
2741 object->lightDirn[0] = pLight->Direction.x;
2742 object->lightDirn[1] = pLight->Direction.y;
2743 object->lightDirn[2] = pLight->Direction.z;
2744 object->lightDirn[3] = 1.0;
2747 * opengl-ish and d3d-ish spot lights use too different models for the
2748 * light "intensity" as a function of the angle towards the main light direction,
2749 * so we only can approximate very roughly.
2750 * however spot lights are rather rarely used in games (if ever used at all).
2751 * furthermore if still used, probably nobody pays attention to such details.
2753 if (pLight->Falloff == 0) {
2754 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2755 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2756 * will always be 1.0 for both of them, and we don't have to care for the
2757 * rest of the rather complex calculation
2759 object->exponent = 0;
2761 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2762 if (rho < 0.0001) rho = 0.0001f;
2763 object->exponent = -0.3/log(cos(rho/2));
2765 if (object->exponent > 128.0) {
2766 object->exponent = 128.0;
2768 object->cutoff = pLight->Phi*90/M_PI;
2774 FIXME("Unrecognized light type %d\n", pLight->Type);
2777 /* Update the live definitions if the light is currently assigned a glIndex */
2778 if (object->glIndex != -1 && !This->isRecordingState) {
2779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2784 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2785 PLIGHTINFOEL *lightInfo = NULL;
2786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2787 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2789 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2791 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2792 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2793 if(lightInfo->OriginalIndex == Index) break;
2797 if (lightInfo == NULL) {
2798 TRACE("Light information requested but light not defined\n");
2799 return WINED3DERR_INVALIDCALL;
2802 *pLight = lightInfo->OriginalParms;
2807 * Get / Set Light Enable
2808 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2810 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2811 PLIGHTINFOEL *lightInfo = NULL;
2812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2815 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2817 /* Tests show true = 128...not clear why */
2818 Enable = Enable? 128: 0;
2820 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2821 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2822 if(lightInfo->OriginalIndex == Index) break;
2825 TRACE("Found light: %p\n", lightInfo);
2827 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2828 if (lightInfo == NULL) {
2830 TRACE("Light enabled requested but light not defined, so defining one!\n");
2831 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2833 /* Search for it again! Should be fairly quick as near head of list */
2834 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2835 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2836 if(lightInfo->OriginalIndex == Index) break;
2839 if (lightInfo == NULL) {
2840 FIXME("Adding default lights has failed dismally\n");
2841 return WINED3DERR_INVALIDCALL;
2845 lightInfo->enabledChanged = TRUE;
2847 if(lightInfo->glIndex != -1) {
2848 if(!This->isRecordingState) {
2849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2852 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2853 lightInfo->glIndex = -1;
2855 TRACE("Light already disabled, nothing to do\n");
2857 lightInfo->enabled = FALSE;
2859 lightInfo->enabled = TRUE;
2860 if (lightInfo->glIndex != -1) {
2862 TRACE("Nothing to do as light was enabled\n");
2865 /* Find a free gl light */
2866 for(i = 0; i < This->maxConcurrentLights; i++) {
2867 if(This->stateBlock->activeLights[i] == NULL) {
2868 This->stateBlock->activeLights[i] = lightInfo;
2869 lightInfo->glIndex = i;
2873 if(lightInfo->glIndex == -1) {
2874 /* Our tests show that Windows returns D3D_OK in this situation, even with
2875 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2876 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2877 * as well for those lights.
2879 * TODO: Test how this affects rendering
2881 FIXME("Too many concurrently active lights\n");
2885 /* i == lightInfo->glIndex */
2886 if(!This->isRecordingState) {
2887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2895 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2897 PLIGHTINFOEL *lightInfo = NULL;
2898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2901 TRACE("(%p) : for idx(%d)\n", This, Index);
2903 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2904 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2905 if(lightInfo->OriginalIndex == Index) break;
2909 if (lightInfo == NULL) {
2910 TRACE("Light enabled state requested but light not defined\n");
2911 return WINED3DERR_INVALIDCALL;
2913 /* true is 128 according to SetLightEnable */
2914 *pEnable = lightInfo->enabled ? 128 : 0;
2919 * Get / Set Clip Planes
2921 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2923 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2925 /* Validate Index */
2926 if (Index >= GL_LIMITS(clipplanes)) {
2927 TRACE("Application has requested clipplane this device doesn't support\n");
2928 return WINED3DERR_INVALIDCALL;
2931 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2933 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2934 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2935 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2936 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2937 TRACE("Application is setting old values over, nothing to do\n");
2941 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2942 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2943 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2944 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2946 /* Handle recording of state blocks */
2947 if (This->isRecordingState) {
2948 TRACE("Recording... not performing anything\n");
2952 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
2957 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
2958 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2959 TRACE("(%p) : for idx %d\n", This, Index);
2961 /* Validate Index */
2962 if (Index >= GL_LIMITS(clipplanes)) {
2963 TRACE("Application has requested clipplane this device doesn't support\n");
2964 return WINED3DERR_INVALIDCALL;
2967 pPlane[0] = This->stateBlock->clipplane[Index][0];
2968 pPlane[1] = This->stateBlock->clipplane[Index][1];
2969 pPlane[2] = This->stateBlock->clipplane[Index][2];
2970 pPlane[3] = This->stateBlock->clipplane[Index][3];
2975 * Get / Set Clip Plane Status
2976 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
2978 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
2979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2980 FIXME("(%p) : stub\n", This);
2981 if (NULL == pClipStatus) {
2982 return WINED3DERR_INVALIDCALL;
2984 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
2985 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
2989 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
2990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2991 FIXME("(%p) : stub\n", This);
2992 if (NULL == pClipStatus) {
2993 return WINED3DERR_INVALIDCALL;
2995 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
2996 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3001 * Get / Set Material
3003 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3006 This->updateStateBlock->changed.material = TRUE;
3007 This->updateStateBlock->material = *pMaterial;
3009 /* Handle recording of state blocks */
3010 if (This->isRecordingState) {
3011 TRACE("Recording... not performing anything\n");
3015 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3019 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3021 *pMaterial = This->updateStateBlock->material;
3022 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3023 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3024 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3025 pMaterial->Ambient.b, pMaterial->Ambient.a);
3026 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3027 pMaterial->Specular.b, pMaterial->Specular.a);
3028 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3029 pMaterial->Emissive.b, pMaterial->Emissive.a);
3030 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 IWineD3DIndexBuffer *oldIdxs;
3042 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3043 oldIdxs = This->updateStateBlock->pIndexData;
3045 This->updateStateBlock->changed.indices = TRUE;
3046 This->updateStateBlock->pIndexData = pIndexData;
3048 /* Handle recording of state blocks */
3049 if (This->isRecordingState) {
3050 TRACE("Recording... not performing anything\n");
3051 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3052 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3056 if(oldIdxs != pIndexData) {
3057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3058 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3059 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 *ppIndexData = This->stateBlock->pIndexData;
3069 /* up ref count on ppindexdata */
3071 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3072 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3074 TRACE("(%p) No index data set\n", This);
3076 TRACE("Returning %p\n", *ppIndexData);
3081 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3082 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3084 TRACE("(%p)->(%d)\n", This, BaseIndex);
3086 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3087 TRACE("Application is setting the old value over, nothing to do\n");
3091 This->updateStateBlock->baseVertexIndex = BaseIndex;
3093 if (This->isRecordingState) {
3094 TRACE("Recording... not performing anything\n");
3097 /* The base vertex index affects the stream sources */
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3102 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 TRACE("(%p) : base_index %p\n", This, base_index);
3106 *base_index = This->stateBlock->baseVertexIndex;
3108 TRACE("Returning %u\n", *base_index);
3114 * Get / Set Viewports
3116 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3117 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3119 TRACE("(%p)\n", This);
3120 This->updateStateBlock->changed.viewport = TRUE;
3121 This->updateStateBlock->viewport = *pViewport;
3123 /* Handle recording of state blocks */
3124 if (This->isRecordingState) {
3125 TRACE("Recording... not performing anything\n");
3129 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3130 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3137 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 TRACE("(%p)\n", This);
3140 *pViewport = This->stateBlock->viewport;
3145 * Get / Set Render States
3146 * TODO: Verify against dx9 definitions
3148 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3151 DWORD oldValue = This->stateBlock->renderState[State];
3153 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3155 This->updateStateBlock->changed.renderState[State] = TRUE;
3156 This->updateStateBlock->renderState[State] = Value;
3158 /* Handle recording of state blocks */
3159 if (This->isRecordingState) {
3160 TRACE("Recording... not performing anything\n");
3164 /* Compared here and not before the assignment to allow proper stateblock recording */
3165 if(Value == oldValue) {
3166 TRACE("Application is setting the old value over, nothing to do\n");
3168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3174 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3176 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3177 *pValue = This->stateBlock->renderState[State];
3182 * Get / Set Sampler States
3183 * TODO: Verify against dx9 definitions
3186 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3190 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3191 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3193 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3194 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3197 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3198 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3199 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3202 * SetSampler is designed to allow for more than the standard up to 8 textures
3203 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3204 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3206 * http://developer.nvidia.com/object/General_FAQ.html#t6
3208 * There are two new settings for GForce
3210 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3211 * and the texture one:
3212 * GL_MAX_TEXTURE_COORDS_ARB.
3213 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3216 oldValue = This->stateBlock->samplerState[Sampler][Type];
3217 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3218 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3220 /* Handle recording of state blocks */
3221 if (This->isRecordingState) {
3222 TRACE("Recording... not performing anything\n");
3226 if(oldValue == Value) {
3227 TRACE("Application is setting the old value over, nothing to do\n");
3231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3236 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3237 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3239 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3240 This, Sampler, debug_d3dsamplerstate(Type), Type);
3242 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3243 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3246 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3247 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3248 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3250 *Value = This->stateBlock->samplerState[Sampler][Type];
3251 TRACE("(%p) : Returning %#x\n", This, *Value);
3256 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 This->updateStateBlock->changed.scissorRect = TRUE;
3260 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3261 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3264 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3266 if(This->isRecordingState) {
3267 TRACE("Recording... not performing anything\n");
3271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3276 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3277 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 *pRect = This->updateStateBlock->scissorRect;
3280 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3284 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3286 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3288 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3290 This->updateStateBlock->vertexDecl = pDecl;
3291 This->updateStateBlock->changed.vertexDecl = TRUE;
3293 if (This->isRecordingState) {
3294 TRACE("Recording... not performing anything\n");
3296 } else if(pDecl == oldDecl) {
3297 /* Checked after the assignment to allow proper stateblock recording */
3298 TRACE("Application is setting the old declaration over, nothing to do\n");
3302 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3306 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3311 *ppDecl = This->stateBlock->vertexDecl;
3312 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3316 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3317 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3320 This->updateStateBlock->vertexShader = pShader;
3321 This->updateStateBlock->changed.vertexShader = TRUE;
3323 if (This->isRecordingState) {
3324 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3325 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3326 TRACE("Recording... not performing anything\n");
3328 } else if(oldShader == pShader) {
3329 /* Checked here to allow proper stateblock recording */
3330 TRACE("App is setting the old shader over, nothing to do\n");
3334 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3335 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3336 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3338 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3343 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 if (NULL == ppShader) {
3347 return WINED3DERR_INVALIDCALL;
3349 *ppShader = This->stateBlock->vertexShader;
3350 if( NULL != *ppShader)
3351 IWineD3DVertexShader_AddRef(*ppShader);
3353 TRACE("(%p) : returning %p\n", This, *ppShader);
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3358 IWineD3DDevice *iface,
3360 CONST BOOL *srcData,
3363 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 int i, cnt = min(count, MAX_CONST_B - start);
3366 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3367 iface, srcData, start, count);
3369 if (srcData == NULL || cnt < 0)
3370 return WINED3DERR_INVALIDCALL;
3372 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3373 for (i = 0; i < cnt; i++)
3374 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3376 for (i = start; i < cnt + start; ++i) {
3377 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3380 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3385 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3386 IWineD3DDevice *iface,
3391 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 int cnt = min(count, MAX_CONST_B - start);
3394 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3395 iface, dstData, start, count);
3397 if (dstData == NULL || cnt < 0)
3398 return WINED3DERR_INVALIDCALL;
3400 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3404 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3405 IWineD3DDevice *iface,
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3411 int i, cnt = min(count, MAX_CONST_I - start);
3413 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3414 iface, srcData, start, count);
3416 if (srcData == NULL || cnt < 0)
3417 return WINED3DERR_INVALIDCALL;
3419 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3420 for (i = 0; i < cnt; i++)
3421 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3422 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3424 for (i = start; i < cnt + start; ++i) {
3425 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3433 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3434 IWineD3DDevice *iface,
3439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3440 int cnt = min(count, MAX_CONST_I - start);
3442 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3443 iface, dstData, start, count);
3445 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3446 return WINED3DERR_INVALIDCALL;
3448 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3452 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3453 IWineD3DDevice *iface,
3455 CONST float *srcData,
3458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3461 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3462 iface, srcData, start, count);
3464 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3465 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3466 return WINED3DERR_INVALIDCALL;
3468 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3470 for (i = 0; i < count; i++)
3471 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3472 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3475 for (i = start; i < count + start; ++i) {
3476 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3477 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3478 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3479 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3480 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3482 ptr->idx[ptr->count++] = i;
3483 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3492 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3493 IWineD3DDevice *iface,
3495 CONST float *srcData,
3498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3501 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3502 iface, srcData, start, count);
3504 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3505 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3506 return WINED3DERR_INVALIDCALL;
3508 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3510 for (i = 0; i < count; i++)
3511 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3512 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3515 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3516 * context. On a context switch the old context will be fully dirtified
3518 memset(This->activeContext->vshader_const_dirty + start, 1,
3519 sizeof(*This->activeContext->vshader_const_dirty) * count);
3520 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3527 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3528 IWineD3DDevice *iface,
3533 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3534 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3536 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3537 iface, dstData, start, count);
3539 if (dstData == NULL || cnt < 0)
3540 return WINED3DERR_INVALIDCALL;
3542 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3546 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3548 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3553 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3554 int i = This->rev_tex_unit_map[unit];
3555 int j = This->texUnitMap[stage];
3557 This->texUnitMap[stage] = unit;
3558 if (i != -1 && i != stage) {
3559 This->texUnitMap[i] = -1;
3562 This->rev_tex_unit_map[unit] = stage;
3563 if (j != -1 && j != unit) {
3564 This->rev_tex_unit_map[j] = -1;
3568 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3571 for (i = 0; i < MAX_TEXTURES; ++i) {
3572 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3573 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3574 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3575 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3576 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3577 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3578 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3579 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3581 if (color_op == WINED3DTOP_DISABLE) {
3582 /* Not used, and disable higher stages */
3583 while (i < MAX_TEXTURES) {
3584 This->fixed_function_usage_map[i] = FALSE;
3590 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3591 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3592 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3593 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3594 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3595 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3596 This->fixed_function_usage_map[i] = TRUE;
3598 This->fixed_function_usage_map[i] = FALSE;
3601 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3602 This->fixed_function_usage_map[i+1] = TRUE;
3607 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3610 device_update_fixed_function_usage_map(This);
3612 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3613 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3614 if (!This->fixed_function_usage_map[i]) continue;
3616 if (This->texUnitMap[i] != i) {
3617 device_map_stage(This, i, i);
3618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3619 markTextureStagesDirty(This, i);
3625 /* Now work out the mapping */
3627 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3628 if (!This->fixed_function_usage_map[i]) continue;
3630 if (This->texUnitMap[i] != tex) {
3631 device_map_stage(This, i, tex);
3632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3633 markTextureStagesDirty(This, i);
3640 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3641 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3644 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3645 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3646 device_map_stage(This, i, i);
3647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3648 if (i < MAX_TEXTURES) {
3649 markTextureStagesDirty(This, i);
3655 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3656 int current_mapping = This->rev_tex_unit_map[unit];
3658 if (current_mapping == -1) {
3659 /* Not currently used */
3663 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3664 /* Used by a fragment sampler */
3666 if (!pshader_sampler_tokens) {
3667 /* No pixel shader, check fixed function */
3668 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3671 /* Pixel shader, check the shader's sampler map */
3672 return !pshader_sampler_tokens[current_mapping];
3675 /* Used by a vertex sampler */
3676 return !vshader_sampler_tokens[current_mapping];
3679 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3680 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3681 DWORD *pshader_sampler_tokens = NULL;
3682 int start = GL_LIMITS(combined_samplers) - 1;
3686 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3688 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3689 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3690 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3693 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3694 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3695 if (vshader_sampler_tokens[i]) {
3696 if (This->texUnitMap[vsampler_idx] != -1) {
3697 /* Already mapped somewhere */
3701 while (start >= 0) {
3702 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3703 device_map_stage(This, vsampler_idx, start);
3704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3716 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3717 BOOL vs = use_vs(This);
3718 BOOL ps = use_ps(This);
3721 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3722 * that would be really messy and require shader recompilation
3723 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3724 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3727 device_map_psamplers(This);
3729 device_map_fixed_function_samplers(This);
3733 device_map_vsamplers(This, ps);
3737 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3739 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3740 This->updateStateBlock->pixelShader = pShader;
3741 This->updateStateBlock->changed.pixelShader = TRUE;
3743 /* Handle recording of state blocks */
3744 if (This->isRecordingState) {
3745 TRACE("Recording... not performing anything\n");
3748 if (This->isRecordingState) {
3749 TRACE("Recording... not performing anything\n");
3750 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3751 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3755 if(pShader == oldShader) {
3756 TRACE("App is setting the old pixel shader over, nothing to do\n");
3760 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3761 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3763 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3764 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3769 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3772 if (NULL == ppShader) {
3773 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3774 return WINED3DERR_INVALIDCALL;
3777 *ppShader = This->stateBlock->pixelShader;
3778 if (NULL != *ppShader) {
3779 IWineD3DPixelShader_AddRef(*ppShader);
3781 TRACE("(%p) : returning %p\n", This, *ppShader);
3785 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3786 IWineD3DDevice *iface,
3788 CONST BOOL *srcData,
3791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3792 int i, cnt = min(count, MAX_CONST_B - start);
3794 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3795 iface, srcData, start, count);
3797 if (srcData == NULL || cnt < 0)
3798 return WINED3DERR_INVALIDCALL;
3800 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3801 for (i = 0; i < cnt; i++)
3802 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3804 for (i = start; i < cnt + start; ++i) {
3805 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3813 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3814 IWineD3DDevice *iface,
3819 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3820 int cnt = min(count, MAX_CONST_B - start);
3822 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3823 iface, dstData, start, count);
3825 if (dstData == NULL || cnt < 0)
3826 return WINED3DERR_INVALIDCALL;
3828 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3832 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3833 IWineD3DDevice *iface,
3838 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3839 int i, cnt = min(count, MAX_CONST_I - start);
3841 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3842 iface, srcData, start, count);
3844 if (srcData == NULL || cnt < 0)
3845 return WINED3DERR_INVALIDCALL;
3847 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3848 for (i = 0; i < cnt; i++)
3849 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3850 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3852 for (i = start; i < cnt + start; ++i) {
3853 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3861 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3862 IWineD3DDevice *iface,
3867 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3868 int cnt = min(count, MAX_CONST_I - start);
3870 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3871 iface, dstData, start, count);
3873 if (dstData == NULL || cnt < 0)
3874 return WINED3DERR_INVALIDCALL;
3876 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3880 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3881 IWineD3DDevice *iface,
3883 CONST float *srcData,
3886 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3889 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3890 iface, srcData, start, count);
3892 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3893 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3894 return WINED3DERR_INVALIDCALL;
3896 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3898 for (i = 0; i < count; i++)
3899 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3900 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3903 for (i = start; i < count + start; ++i) {
3904 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3905 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3906 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3907 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3908 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3910 ptr->idx[ptr->count++] = i;
3911 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3915 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3920 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3921 IWineD3DDevice *iface,
3923 CONST float *srcData,
3926 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3929 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3930 iface, srcData, start, count);
3932 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3933 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3934 return WINED3DERR_INVALIDCALL;
3936 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3938 for (i = 0; i < count; i++)
3939 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3940 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3943 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3944 * context. On a context switch the old context will be fully dirtified
3946 memset(This->activeContext->pshader_const_dirty + start, 1,
3947 sizeof(*This->activeContext->pshader_const_dirty) * count);
3948 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
3950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3955 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3956 IWineD3DDevice *iface,
3961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3962 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
3964 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3965 iface, dstData, start, count);
3967 if (dstData == NULL || cnt < 0)
3968 return WINED3DERR_INVALIDCALL;
3970 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3974 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
3976 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
3977 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
3979 DWORD DestFVF = dest->fvf;
3981 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
3985 if (lpStrideData->u.s.normal.lpData) {
3986 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
3989 if (lpStrideData->u.s.position.lpData == NULL) {
3990 ERR("Source has no position mask\n");
3991 return WINED3DERR_INVALIDCALL;
3994 /* We might access VBOs from this code, so hold the lock */
3997 if (dest->resource.allocatedMemory == NULL) {
3998 /* This may happen if we do direct locking into a vbo. Unlikely,
3999 * but theoretically possible(ddraw processvertices test)
4001 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4002 if(!dest->resource.allocatedMemory) {
4004 ERR("Out of memory\n");
4005 return E_OUTOFMEMORY;
4009 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4010 checkGLcall("glBindBufferARB");
4011 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4013 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4015 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4016 checkGLcall("glUnmapBufferARB");
4020 /* Get a pointer into the destination vbo(create one if none exists) and
4021 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4023 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4024 dest->Flags |= VBFLAG_CREATEVBO;
4025 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4029 unsigned char extrabytes = 0;
4030 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4031 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4032 * this may write 4 extra bytes beyond the area that should be written
4034 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4035 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4036 if(!dest_conv_addr) {
4037 ERR("Out of memory\n");
4038 /* Continue without storing converted vertices */
4040 dest_conv = dest_conv_addr;
4044 * a) WINED3DRS_CLIPPING is enabled
4045 * b) WINED3DVOP_CLIP is passed
4047 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4048 static BOOL warned = FALSE;
4050 * The clipping code is not quite correct. Some things need
4051 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4052 * so disable clipping for now.
4053 * (The graphics in Half-Life are broken, and my processvertices
4054 * test crashes with IDirect3DDevice3)
4060 FIXME("Clipping is broken and disabled for now\n");
4062 } else doClip = FALSE;
4063 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4065 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4068 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4069 WINED3DTS_PROJECTION,
4071 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4072 WINED3DTS_WORLDMATRIX(0),
4075 TRACE("View mat:\n");
4076 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);
4077 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);
4078 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);
4079 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);
4081 TRACE("Proj mat:\n");
4082 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);
4083 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);
4084 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);
4085 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);
4087 TRACE("World mat:\n");
4088 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);
4089 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);
4090 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);
4091 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);
4093 /* Get the viewport */
4094 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4095 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4096 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4098 multiply_matrix(&mat,&view_mat,&world_mat);
4099 multiply_matrix(&mat,&proj_mat,&mat);
4101 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4103 for (i = 0; i < dwCount; i+= 1) {
4104 unsigned int tex_index;
4106 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4107 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4108 /* The position first */
4110 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4112 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4114 /* Multiplication with world, view and projection matrix */
4115 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);
4116 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);
4117 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);
4118 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);
4120 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4122 /* WARNING: The following things are taken from d3d7 and were not yet checked
4123 * against d3d8 or d3d9!
4126 /* Clipping conditions: From msdn
4128 * A vertex is clipped if it does not match the following requirements
4132 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4134 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4135 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4140 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4141 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4144 /* "Normal" viewport transformation (not clipped)
4145 * 1) The values are divided by rhw
4146 * 2) The y axis is negative, so multiply it with -1
4147 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4148 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4149 * 4) Multiply x with Width/2 and add Width/2
4150 * 5) The same for the height
4151 * 6) Add the viewpoint X and Y to the 2D coordinates and
4152 * The minimum Z value to z
4153 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4155 * Well, basically it's simply a linear transformation into viewport
4167 z *= vp.MaxZ - vp.MinZ;
4169 x += vp.Width / 2 + vp.X;
4170 y += vp.Height / 2 + vp.Y;
4175 /* That vertex got clipped
4176 * Contrary to OpenGL it is not dropped completely, it just
4177 * undergoes a different calculation.
4179 TRACE("Vertex got clipped\n");
4186 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4187 * outside of the main vertex buffer memory. That needs some more
4192 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4195 ( (float *) dest_ptr)[0] = x;
4196 ( (float *) dest_ptr)[1] = y;
4197 ( (float *) dest_ptr)[2] = z;
4198 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4200 dest_ptr += 3 * sizeof(float);
4202 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4203 dest_ptr += sizeof(float);
4208 ( (float *) dest_conv)[0] = x * w;
4209 ( (float *) dest_conv)[1] = y * w;
4210 ( (float *) dest_conv)[2] = z * w;
4211 ( (float *) dest_conv)[3] = w;
4213 dest_conv += 3 * sizeof(float);
4215 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4216 dest_conv += sizeof(float);
4220 if (DestFVF & WINED3DFVF_PSIZE) {
4221 dest_ptr += sizeof(DWORD);
4222 if(dest_conv) dest_conv += sizeof(DWORD);
4224 if (DestFVF & WINED3DFVF_NORMAL) {
4226 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4227 /* AFAIK this should go into the lighting information */
4228 FIXME("Didn't expect the destination to have a normal\n");
4229 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4231 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4235 if (DestFVF & WINED3DFVF_DIFFUSE) {
4237 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4239 static BOOL warned = FALSE;
4242 ERR("No diffuse color in source, but destination has one\n");
4246 *( (DWORD *) dest_ptr) = 0xffffffff;
4247 dest_ptr += sizeof(DWORD);
4250 *( (DWORD *) dest_conv) = 0xffffffff;
4251 dest_conv += sizeof(DWORD);
4255 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4257 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4258 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4259 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4260 dest_conv += sizeof(DWORD);
4265 if (DestFVF & WINED3DFVF_SPECULAR) {
4266 /* What's the color value in the feedback buffer? */
4268 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4270 static BOOL warned = FALSE;
4273 ERR("No specular color in source, but destination has one\n");
4277 *( (DWORD *) dest_ptr) = 0xFF000000;
4278 dest_ptr += sizeof(DWORD);
4281 *( (DWORD *) dest_conv) = 0xFF000000;
4282 dest_conv += sizeof(DWORD);
4286 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4288 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4289 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4290 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4291 dest_conv += sizeof(DWORD);
4296 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4298 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4299 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4301 ERR("No source texture, but destination requests one\n");
4302 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4303 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4306 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4308 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4315 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4316 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4317 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4318 dwCount * get_flexible_vertex_size(DestFVF),
4320 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4321 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4328 #undef copy_and_next
4330 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4332 WineDirect3DVertexStridedData strided;
4333 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4334 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4337 ERR("Output vertex declaration not implemented yet\n");
4340 /* Need any context to write to the vbo. */
4341 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4343 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4344 * control the streamIsUP flag, thus restore it afterwards.
4346 This->stateBlock->streamIsUP = FALSE;
4347 memset(&strided, 0, sizeof(strided));
4348 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4349 This->stateBlock->streamIsUP = streamWasUP;
4351 if(vbo || SrcStartIndex) {
4353 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4354 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4356 * Also get the start index in, but only loop over all elements if there's something to add at all.
4358 #define FIXSRC(type) \
4359 if(strided.u.s.type.VBO) { \
4360 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4361 strided.u.s.type.VBO = 0; \
4362 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4364 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4368 if(strided.u.s.type.lpData) { \
4369 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4372 FIXSRC(blendWeights);
4373 FIXSRC(blendMatrixIndices);
4378 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4379 FIXSRC(texCoords[i]);
4392 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4396 * Get / Set Texture Stage States
4397 * TODO: Verify against dx9 definitions
4399 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4401 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4403 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4405 if (Stage >= MAX_TEXTURES) {
4406 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4410 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4411 This->updateStateBlock->textureState[Stage][Type] = Value;
4413 if (This->isRecordingState) {
4414 TRACE("Recording... not performing anything\n");
4418 /* Checked after the assignments to allow proper stateblock recording */
4419 if(oldValue == Value) {
4420 TRACE("App is setting the old value over, nothing to do\n");
4424 if(Stage > This->stateBlock->lowest_disabled_stage &&
4425 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4426 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4427 * Changes in other states are important on disabled stages too
4432 if(Type == WINED3DTSS_COLOROP) {
4435 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4436 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4437 * they have to be disabled
4439 * The current stage is dirtified below.
4441 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4442 TRACE("Additionally dirtifying stage %d\n", i);
4443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4445 This->stateBlock->lowest_disabled_stage = Stage;
4446 TRACE("New lowest disabled: %d\n", Stage);
4447 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4448 /* Previously disabled stage enabled. Stages above it may need enabling
4449 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4450 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4452 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4455 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4456 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4459 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4462 This->stateBlock->lowest_disabled_stage = i;
4463 TRACE("New lowest disabled: %d\n", i);
4465 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4466 /* TODO: Built a stage -> texture unit mapping for register combiners */
4470 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4475 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4478 *pValue = This->updateStateBlock->textureState[Stage][Type];
4485 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4486 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4487 IWineD3DBaseTexture *oldTexture;
4489 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4491 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4492 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4495 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4496 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4497 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4500 oldTexture = This->updateStateBlock->textures[Stage];
4502 if(pTexture != NULL) {
4503 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4505 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4506 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4507 return WINED3DERR_INVALIDCALL;
4509 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4512 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4513 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4515 This->updateStateBlock->changed.textures[Stage] = TRUE;
4516 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4517 This->updateStateBlock->textures[Stage] = pTexture;
4519 /* Handle recording of state blocks */
4520 if (This->isRecordingState) {
4521 TRACE("Recording... not performing anything\n");
4525 if(oldTexture == pTexture) {
4526 TRACE("App is setting the same texture again, nothing to do\n");
4530 /** NOTE: MSDN says that setTexture increases the reference count,
4531 * and that the application must set the texture back to null (or have a leaky application),
4532 * This means we should pass the refcount up to the parent
4533 *******************************/
4534 if (NULL != This->updateStateBlock->textures[Stage]) {
4535 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4536 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4538 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4539 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4540 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4541 * so the COLOROP and ALPHAOP have to be dirtified.
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4544 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4546 if(bindCount == 1) {
4547 new->baseTexture.sampler = Stage;
4549 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4553 if (NULL != oldTexture) {
4554 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4555 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4557 IWineD3DBaseTexture_Release(oldTexture);
4558 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4563 if(bindCount && old->baseTexture.sampler == Stage) {
4565 /* Have to do a search for the other sampler(s) where the texture is bound to
4566 * Shouldn't happen as long as apps bind a texture only to one stage
4568 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4569 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4570 if(This->updateStateBlock->textures[i] == oldTexture) {
4571 old->baseTexture.sampler = i;
4578 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4583 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4586 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4588 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4589 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4592 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4593 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4594 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4597 *ppTexture=This->stateBlock->textures[Stage];
4599 IWineD3DBaseTexture_AddRef(*ppTexture);
4601 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4609 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4610 IWineD3DSurface **ppBackBuffer) {
4611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4612 IWineD3DSwapChain *swapChain;
4615 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4617 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4618 if (hr == WINED3D_OK) {
4619 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4620 IWineD3DSwapChain_Release(swapChain);
4622 *ppBackBuffer = NULL;
4627 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 WARN("(%p) : stub, calling idirect3d for now\n", This);
4630 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4633 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 IWineD3DSwapChain *swapChain;
4638 if(iSwapChain > 0) {
4639 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4640 if (hr == WINED3D_OK) {
4641 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4642 IWineD3DSwapChain_Release(swapChain);
4644 FIXME("(%p) Error getting display mode\n", This);
4647 /* Don't read the real display mode,
4648 but return the stored mode instead. X11 can't change the color
4649 depth, and some apps are pretty angry if they SetDisplayMode from
4650 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4652 Also don't relay to the swapchain because with ddraw it's possible
4653 that there isn't a swapchain at all */
4654 pMode->Width = This->ddraw_width;
4655 pMode->Height = This->ddraw_height;
4656 pMode->Format = This->ddraw_format;
4657 pMode->RefreshRate = 0;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 TRACE("(%p)->(%p)\n", This, hWnd);
4668 if(This->ddraw_fullscreen) {
4669 if(This->ddraw_window && This->ddraw_window != hWnd) {
4670 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4672 if(hWnd && This->ddraw_window != hWnd) {
4673 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4677 This->ddraw_window = hWnd;
4681 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4683 TRACE("(%p)->(%p)\n", This, hWnd);
4685 *hWnd = This->ddraw_window;
4690 * Stateblock related functions
4693 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 IWineD3DStateBlockImpl *object;
4696 HRESULT temp_result;
4699 TRACE("(%p)\n", This);
4701 if (This->isRecordingState) {
4702 return WINED3DERR_INVALIDCALL;
4705 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4706 if (NULL == object ) {
4707 FIXME("(%p)Error allocating memory for stateblock\n", This);
4708 return E_OUTOFMEMORY;
4710 TRACE("(%p) created object %p\n", This, object);
4711 object->wineD3DDevice= This;
4712 /** FIXME: object->parent = parent; **/
4713 object->parent = NULL;
4714 object->blockType = WINED3DSBT_RECORDED;
4716 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4718 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4719 list_init(&object->lightMap[i]);
4722 temp_result = allocate_shader_constants(object);
4723 if (WINED3D_OK != temp_result)
4726 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4727 This->updateStateBlock = object;
4728 This->isRecordingState = TRUE;
4730 TRACE("(%p) recording stateblock %p\n",This , object);
4734 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4735 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4737 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4739 if (!This->isRecordingState) {
4740 FIXME("(%p) not recording! returning error\n", This);
4741 *ppStateBlock = NULL;
4742 return WINED3DERR_INVALIDCALL;
4745 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4746 if(object->changed.renderState[i]) {
4747 object->contained_render_states[object->num_contained_render_states] = i;
4748 object->num_contained_render_states++;
4751 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4752 if(object->changed.transform[i]) {
4753 object->contained_transform_states[object->num_contained_transform_states] = i;
4754 object->num_contained_transform_states++;
4757 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4758 if(object->changed.vertexShaderConstantsF[i]) {
4759 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4760 object->num_contained_vs_consts_f++;
4763 for(i = 0; i < MAX_CONST_I; i++) {
4764 if(object->changed.vertexShaderConstantsI[i]) {
4765 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4766 object->num_contained_vs_consts_i++;
4769 for(i = 0; i < MAX_CONST_B; i++) {
4770 if(object->changed.vertexShaderConstantsB[i]) {
4771 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4772 object->num_contained_vs_consts_b++;
4775 for(i = 0; i < MAX_CONST_I; i++) {
4776 if(object->changed.pixelShaderConstantsI[i]) {
4777 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4778 object->num_contained_ps_consts_i++;
4781 for(i = 0; i < MAX_CONST_B; i++) {
4782 if(object->changed.pixelShaderConstantsB[i]) {
4783 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4784 object->num_contained_ps_consts_b++;
4787 for(i = 0; i < MAX_TEXTURES; i++) {
4788 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4789 if(object->changed.textureState[i][j]) {
4790 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4791 object->contained_tss_states[object->num_contained_tss_states].state = j;
4792 object->num_contained_tss_states++;
4796 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4797 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4798 if(object->changed.samplerState[i][j]) {
4799 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4800 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4801 object->num_contained_sampler_states++;
4806 *ppStateBlock = (IWineD3DStateBlock*) object;
4807 This->isRecordingState = FALSE;
4808 This->updateStateBlock = This->stateBlock;
4809 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4810 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4811 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4816 * Scene related functions
4818 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4819 /* At the moment we have no need for any functionality at the beginning
4821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4822 TRACE("(%p)\n", This);
4825 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4826 return WINED3DERR_INVALIDCALL;
4828 This->inScene = TRUE;
4832 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4833 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4834 TRACE("(%p)\n", This);
4836 if(!This->inScene) {
4837 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4838 return WINED3DERR_INVALIDCALL;
4841 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4842 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4845 checkGLcall("glFlush");
4848 This->inScene = FALSE;
4852 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4853 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4854 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4856 IWineD3DSwapChain *swapChain = NULL;
4858 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4860 TRACE("(%p) Presenting the frame\n", This);
4862 for(i = 0 ; i < swapchains ; i ++) {
4864 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4865 TRACE("presentinng chain %d, %p\n", i, swapChain);
4866 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4867 IWineD3DSwapChain_Release(swapChain);
4873 /* Not called from the VTable (internal subroutine) */
4874 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4875 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4876 float Z, DWORD Stencil) {
4877 GLbitfield glMask = 0;
4879 WINED3DRECT curRect;
4881 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4882 UINT drawable_width, drawable_height;
4883 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4885 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4886 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4887 * for the cleared parts, and the untouched parts.
4889 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4890 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4891 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4892 * checking all this if the dest surface is in the drawable anyway.
4894 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4896 if(vp->X != 0 || vp->Y != 0 ||
4897 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4898 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4901 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4902 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4903 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4904 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4905 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4908 if(Count > 0 && pRects && (
4909 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4910 pRects[0].x2 < target->currentDesc.Width ||
4911 pRects[0].y2 < target->currentDesc.Height)) {
4912 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4919 target->get_drawable_size(target, &drawable_width, &drawable_height);
4921 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4924 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4925 apply_fbo_state((IWineD3DDevice *) This);
4928 /* Only set the values up once, as they are not changing */
4929 if (Flags & WINED3DCLEAR_STENCIL) {
4930 glClearStencil(Stencil);
4931 checkGLcall("glClearStencil");
4932 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4933 glStencilMask(0xFFFFFFFF);
4936 if (Flags & WINED3DCLEAR_ZBUFFER) {
4937 glDepthMask(GL_TRUE);
4939 checkGLcall("glClearDepth");
4940 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4943 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4944 if(vp->X != 0 || vp->Y != 0 ||
4945 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4946 depth_copy((IWineD3DDevice *) This);
4948 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4949 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4950 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4951 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4952 depth_copy((IWineD3DDevice *) This);
4954 else if(Count > 0 && pRects && (
4955 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4956 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4957 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4958 depth_copy((IWineD3DDevice *) This);
4961 This->depth_copy_state = WINED3D_DCS_INITIAL;
4964 if (Flags & WINED3DCLEAR_TARGET) {
4965 TRACE("Clearing screen with glClear to color %x\n", Color);
4966 glClearColor(D3DCOLOR_R(Color),
4970 checkGLcall("glClearColor");
4972 /* Clear ALL colors! */
4973 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4974 glMask = glMask | GL_COLOR_BUFFER_BIT;
4977 vp_rect.left = vp->X;
4978 vp_rect.top = vp->Y;
4979 vp_rect.right = vp->X + vp->Width;
4980 vp_rect.bottom = vp->Y + vp->Height;
4981 if (!(Count > 0 && pRects)) {
4982 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4983 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4985 if(This->render_offscreen) {
4986 glScissor(vp_rect.left, vp_rect.top,
4987 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4989 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
4990 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
4992 checkGLcall("glScissor");
4994 checkGLcall("glClear");
4996 /* Now process each rect in turn */
4997 for (i = 0; i < Count; i++) {
4998 /* Note gl uses lower left, width/height */
4999 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5000 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5001 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5003 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5004 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5005 curRect.x1, (target->currentDesc.Height - curRect.y2),
5006 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5008 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5009 * The rectangle is not cleared, no error is returned, but further rectanlges are
5010 * still cleared if they are valid
5012 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5013 TRACE("Rectangle with negative dimensions, ignoring\n");
5017 if(This->render_offscreen) {
5018 glScissor(curRect.x1, curRect.y1,
5019 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5021 glScissor(curRect.x1, drawable_height - curRect.y2,
5022 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5024 checkGLcall("glScissor");
5027 checkGLcall("glClear");
5031 /* Restore the old values (why..?) */
5032 if (Flags & WINED3DCLEAR_STENCIL) {
5033 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5035 if (Flags & WINED3DCLEAR_TARGET) {
5036 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5037 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5038 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5039 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5040 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5042 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5043 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5045 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5046 /* TODO: Move the fbo logic into ModifyLocation() */
5047 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5048 target->Flags |= SFLAG_INTEXTURE;
5056 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5057 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5059 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5061 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5062 Count, pRects, Flags, Color, Z, Stencil);
5064 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5065 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5066 /* TODO: What about depth stencil buffers without stencil bits? */
5067 return WINED3DERR_INVALIDCALL;
5070 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5076 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5077 UINT PrimitiveCount) {
5079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5081 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5082 debug_d3dprimitivetype(PrimitiveType),
5083 StartVertex, PrimitiveCount);
5085 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5086 if(This->stateBlock->streamIsUP) {
5087 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5088 This->stateBlock->streamIsUP = FALSE;
5091 if(This->stateBlock->loadBaseVertexIndex != 0) {
5092 This->stateBlock->loadBaseVertexIndex = 0;
5093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5095 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5096 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5097 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5101 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5102 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5103 WINED3DPRIMITIVETYPE PrimitiveType,
5104 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5108 IWineD3DIndexBuffer *pIB;
5109 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5112 pIB = This->stateBlock->pIndexData;
5114 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5115 * without an index buffer set. (The first time at least...)
5116 * D3D8 simply dies, but I doubt it can do much harm to return
5117 * D3DERR_INVALIDCALL there as well. */
5118 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5119 return WINED3DERR_INVALIDCALL;
5122 if(This->stateBlock->streamIsUP) {
5123 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5124 This->stateBlock->streamIsUP = FALSE;
5126 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5128 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5129 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5130 minIndex, NumVertices, startIndex, primCount);
5132 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5133 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5139 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5140 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5144 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5145 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5150 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5151 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5152 UINT VertexStreamZeroStride) {
5153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5154 IWineD3DVertexBuffer *vb;
5156 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5157 debug_d3dprimitivetype(PrimitiveType),
5158 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5160 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5161 vb = This->stateBlock->streamSource[0];
5162 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5163 if(vb) IWineD3DVertexBuffer_Release(vb);
5164 This->stateBlock->streamOffset[0] = 0;
5165 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5166 This->stateBlock->streamIsUP = TRUE;
5167 This->stateBlock->loadBaseVertexIndex = 0;
5169 /* TODO: Only mark dirty if drawing from a different UP address */
5170 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5172 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5173 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5175 /* MSDN specifies stream zero settings must be set to NULL */
5176 This->stateBlock->streamStride[0] = 0;
5177 This->stateBlock->streamSource[0] = NULL;
5179 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5180 * the new stream sources or use UP drawing again
5185 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5186 UINT MinVertexIndex, UINT NumVertices,
5187 UINT PrimitiveCount, CONST void* pIndexData,
5188 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5189 UINT VertexStreamZeroStride) {
5191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5192 IWineD3DVertexBuffer *vb;
5193 IWineD3DIndexBuffer *ib;
5195 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5196 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5197 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5198 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5200 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5206 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5207 vb = This->stateBlock->streamSource[0];
5208 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5209 if(vb) IWineD3DVertexBuffer_Release(vb);
5210 This->stateBlock->streamIsUP = TRUE;
5211 This->stateBlock->streamOffset[0] = 0;
5212 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5214 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5215 This->stateBlock->baseVertexIndex = 0;
5216 This->stateBlock->loadBaseVertexIndex = 0;
5217 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5218 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5219 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5221 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5223 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5224 This->stateBlock->streamSource[0] = NULL;
5225 This->stateBlock->streamStride[0] = 0;
5226 ib = This->stateBlock->pIndexData;
5228 IWineD3DIndexBuffer_Release(ib);
5229 This->stateBlock->pIndexData = NULL;
5231 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5232 * SetStreamSource to specify a vertex buffer
5238 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5241 /* Mark the state dirty until we have nicer tracking
5242 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5247 This->stateBlock->baseVertexIndex = 0;
5248 This->up_strided = DrawPrimStrideData;
5249 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5250 This->up_strided = NULL;
5254 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5256 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5258 /* Mark the state dirty until we have nicer tracking
5259 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5263 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5264 This->stateBlock->streamIsUP = TRUE;
5265 This->stateBlock->baseVertexIndex = 0;
5266 This->up_strided = DrawPrimStrideData;
5267 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5268 This->up_strided = NULL;
5272 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5273 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5274 * not callable by the app directly no parameter validation checks are needed here.
5276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5277 WINED3DLOCKED_BOX src;
5278 WINED3DLOCKED_BOX dst;
5280 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5282 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5283 * dirtification to improve loading performance.
5285 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5286 if(FAILED(hr)) return hr;
5287 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5289 IWineD3DVolume_UnlockBox(pSourceVolume);
5293 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5295 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5297 IWineD3DVolume_UnlockBox(pSourceVolume);
5299 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5304 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5305 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5307 HRESULT hr = WINED3D_OK;
5308 WINED3DRESOURCETYPE sourceType;
5309 WINED3DRESOURCETYPE destinationType;
5312 /* TODO: think about moving the code into IWineD3DBaseTexture */
5314 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5316 /* verify that the source and destination textures aren't NULL */
5317 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5318 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5319 This, pSourceTexture, pDestinationTexture);
5320 hr = WINED3DERR_INVALIDCALL;
5323 if (pSourceTexture == pDestinationTexture) {
5324 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5325 This, pSourceTexture, pDestinationTexture);
5326 hr = WINED3DERR_INVALIDCALL;
5328 /* Verify that the source and destination textures are the same type */
5329 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5330 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5332 if (sourceType != destinationType) {
5333 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5335 hr = WINED3DERR_INVALIDCALL;
5338 /* check that both textures have the identical numbers of levels */
5339 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5340 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5341 hr = WINED3DERR_INVALIDCALL;
5344 if (WINED3D_OK == hr) {
5346 /* Make sure that the destination texture is loaded */
5347 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5349 /* Update every surface level of the texture */
5350 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5352 switch (sourceType) {
5353 case WINED3DRTYPE_TEXTURE:
5355 IWineD3DSurface *srcSurface;
5356 IWineD3DSurface *destSurface;
5358 for (i = 0 ; i < levels ; ++i) {
5359 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5360 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5361 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5362 IWineD3DSurface_Release(srcSurface);
5363 IWineD3DSurface_Release(destSurface);
5364 if (WINED3D_OK != hr) {
5365 WARN("(%p) : Call to update surface failed\n", This);
5371 case WINED3DRTYPE_CUBETEXTURE:
5373 IWineD3DSurface *srcSurface;
5374 IWineD3DSurface *destSurface;
5375 WINED3DCUBEMAP_FACES faceType;
5377 for (i = 0 ; i < levels ; ++i) {
5378 /* Update each cube face */
5379 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5380 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5381 if (WINED3D_OK != hr) {
5382 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5384 TRACE("Got srcSurface %p\n", srcSurface);
5386 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5387 if (WINED3D_OK != hr) {
5388 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5390 TRACE("Got desrSurface %p\n", destSurface);
5392 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5393 IWineD3DSurface_Release(srcSurface);
5394 IWineD3DSurface_Release(destSurface);
5395 if (WINED3D_OK != hr) {
5396 WARN("(%p) : Call to update surface failed\n", This);
5404 case WINED3DRTYPE_VOLUMETEXTURE:
5406 IWineD3DVolume *srcVolume = NULL;
5407 IWineD3DVolume *destVolume = NULL;
5409 for (i = 0 ; i < levels ; ++i) {
5410 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5411 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5412 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5413 IWineD3DVolume_Release(srcVolume);
5414 IWineD3DVolume_Release(destVolume);
5415 if (WINED3D_OK != hr) {
5416 WARN("(%p) : Call to update volume failed\n", This);
5424 FIXME("(%p) : Unsupported source and destination type\n", This);
5425 hr = WINED3DERR_INVALIDCALL;
5432 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5433 IWineD3DSwapChain *swapChain;
5435 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5436 if(hr == WINED3D_OK) {
5437 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5438 IWineD3DSwapChain_Release(swapChain);
5443 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5445 /* return a sensible default */
5447 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5448 FIXME("(%p) : stub\n", This);
5452 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5456 if (PaletteNumber >= MAX_PALETTES) {
5457 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5458 return WINED3DERR_INVALIDCALL;
5460 for (j = 0; j < 256; ++j) {
5461 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5462 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5463 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5464 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5466 TRACE("(%p) : returning\n", This);
5470 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5473 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5474 if (PaletteNumber >= MAX_PALETTES) {
5475 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5476 return WINED3DERR_INVALIDCALL;
5478 for (j = 0; j < 256; ++j) {
5479 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5480 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5481 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5482 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5484 TRACE("(%p) : returning\n", This);
5488 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5490 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5491 if (PaletteNumber >= MAX_PALETTES) {
5492 WARN("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5493 return WINED3DERR_INVALIDCALL;
5495 /*TODO: stateblocks */
5496 This->currentPalette = PaletteNumber;
5497 TRACE("(%p) : returning\n", This);
5501 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5503 if (PaletteNumber == NULL) {
5504 WARN("(%p) : returning Invalid Call\n", This);
5505 return WINED3DERR_INVALIDCALL;
5507 /*TODO: stateblocks */
5508 *PaletteNumber = This->currentPalette;
5509 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5513 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5515 static BOOL showFixmes = TRUE;
5517 FIXME("(%p) : stub\n", This);
5521 This->softwareVertexProcessing = bSoftware;
5526 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5528 static BOOL showFixmes = TRUE;
5530 FIXME("(%p) : stub\n", This);
5533 return This->softwareVertexProcessing;
5537 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5538 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5539 IWineD3DSwapChain *swapChain;
5542 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5544 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5545 if(hr == WINED3D_OK){
5546 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5547 IWineD3DSwapChain_Release(swapChain);
5549 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5555 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5557 static BOOL showfixmes = TRUE;
5558 if(nSegments != 0.0f) {
5560 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5567 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5569 static BOOL showfixmes = TRUE;
5571 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5577 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5578 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5579 /** TODO: remove casts to IWineD3DSurfaceImpl
5580 * NOTE: move code to surface to accomplish this
5581 ****************************************/
5582 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5583 int srcWidth, srcHeight;
5584 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5585 WINED3DFORMAT destFormat, srcFormat;
5587 int srcLeft, destLeft, destTop;
5588 WINED3DPOOL srcPool, destPool;
5590 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5591 glDescriptor *glDescription = NULL;
5594 CONVERT_TYPES convert = NO_CONVERSION;
5596 WINED3DSURFACE_DESC winedesc;
5598 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5599 memset(&winedesc, 0, sizeof(winedesc));
5600 winedesc.Width = &srcSurfaceWidth;
5601 winedesc.Height = &srcSurfaceHeight;
5602 winedesc.Pool = &srcPool;
5603 winedesc.Format = &srcFormat;
5605 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5607 winedesc.Width = &destSurfaceWidth;
5608 winedesc.Height = &destSurfaceHeight;
5609 winedesc.Pool = &destPool;
5610 winedesc.Format = &destFormat;
5611 winedesc.Size = &destSize;
5613 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5615 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5616 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5617 return WINED3DERR_INVALIDCALL;
5620 /* This call loads the opengl surface directly, instead of copying the surface to the
5621 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5622 * copy in sysmem and use regular surface loading.
5624 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5625 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5626 if(convert != NO_CONVERSION) {
5627 return IWineD3DSurface_BltFast(pDestinationSurface,
5628 pDestPoint ? pDestPoint->x : 0,
5629 pDestPoint ? pDestPoint->y : 0,
5630 pSourceSurface, (RECT *) pSourceRect, 0);
5633 if (destFormat == WINED3DFMT_UNKNOWN) {
5634 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5635 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5637 /* Get the update surface description */
5638 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5641 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5645 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5646 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5647 checkGLcall("glActiveTextureARB");
5650 /* Make sure the surface is loaded and up to date */
5651 IWineD3DSurface_PreLoad(pDestinationSurface);
5653 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5655 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5656 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5657 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5658 srcLeft = pSourceRect ? pSourceRect->left : 0;
5659 destLeft = pDestPoint ? pDestPoint->x : 0;
5660 destTop = pDestPoint ? pDestPoint->y : 0;
5663 /* This function doesn't support compressed textures
5664 the pitch is just bytesPerPixel * width */
5665 if(srcWidth != srcSurfaceWidth || srcLeft ){
5666 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5667 offset += srcLeft * pSrcSurface->bytesPerPixel;
5668 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5670 /* TODO DXT formats */
5672 if(pSourceRect != NULL && pSourceRect->top != 0){
5673 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5675 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5677 ,glDescription->level
5682 ,glDescription->glFormat
5683 ,glDescription->glType
5684 ,IWineD3DSurface_GetData(pSourceSurface)
5688 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5690 /* need to lock the surface to get the data */
5691 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5694 /* TODO: Cube and volume support */
5696 /* not a whole row so we have to do it a line at a time */
5699 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5700 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5702 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5704 glTexSubImage2D(glDescription->target
5705 ,glDescription->level
5710 ,glDescription->glFormat
5711 ,glDescription->glType
5712 ,data /* could be quicker using */
5717 } else { /* Full width, so just write out the whole texture */
5719 if (WINED3DFMT_DXT1 == destFormat ||
5720 WINED3DFMT_DXT2 == destFormat ||
5721 WINED3DFMT_DXT3 == destFormat ||
5722 WINED3DFMT_DXT4 == destFormat ||
5723 WINED3DFMT_DXT5 == destFormat) {
5724 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5725 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5726 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5727 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5728 } if (destFormat != srcFormat) {
5729 FIXME("Updating mixed format compressed texture is not curretly support\n");
5731 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5732 glDescription->level,
5733 glDescription->glFormatInternal,
5738 IWineD3DSurface_GetData(pSourceSurface));
5741 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5746 glTexSubImage2D(glDescription->target
5747 ,glDescription->level
5752 ,glDescription->glFormat
5753 ,glDescription->glType
5754 ,IWineD3DSurface_GetData(pSourceSurface)
5758 checkGLcall("glTexSubImage2D");
5762 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5768 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5770 struct WineD3DRectPatch *patch;
5774 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5776 if(!(Handle || pRectPatchInfo)) {
5777 /* TODO: Write a test for the return value, thus the FIXME */
5778 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5779 return WINED3DERR_INVALIDCALL;
5783 i = PATCHMAP_HASHFUNC(Handle);
5785 LIST_FOR_EACH(e, &This->patches[i]) {
5786 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5787 if(patch->Handle == Handle) {
5794 TRACE("Patch does not exist. Creating a new one\n");
5795 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5796 patch->Handle = Handle;
5797 list_add_head(&This->patches[i], &patch->entry);
5799 TRACE("Found existing patch %p\n", patch);
5802 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5803 * attributes we have to tesselate, read back, and draw. This needs a patch
5804 * management structure instance. Create one.
5806 * A possible improvement is to check if a vertex shader is used, and if not directly
5809 FIXME("Drawing an uncached patch. This is slow\n");
5810 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5813 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5814 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5815 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5817 TRACE("Tesselation density or patch info changed, retesselating\n");
5819 if(pRectPatchInfo) {
5820 patch->RectPatchInfo = *pRectPatchInfo;
5822 patch->numSegs[0] = pNumSegs[0];
5823 patch->numSegs[1] = pNumSegs[1];
5824 patch->numSegs[2] = pNumSegs[2];
5825 patch->numSegs[3] = pNumSegs[3];
5827 hr = tesselate_rectpatch(This, patch);
5829 WARN("Patch tesselation failed\n");
5831 /* Do not release the handle to store the params of the patch */
5833 HeapFree(GetProcessHeap(), 0, patch);
5839 This->currentPatch = patch;
5840 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5841 This->currentPatch = NULL;
5843 /* Destroy uncached patches */
5845 HeapFree(GetProcessHeap(), 0, patch->mem);
5846 HeapFree(GetProcessHeap(), 0, patch);
5851 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5853 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5854 FIXME("(%p) : Stub\n", This);
5858 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5861 struct WineD3DRectPatch *patch;
5863 TRACE("(%p) Handle(%d)\n", This, Handle);
5865 i = PATCHMAP_HASHFUNC(Handle);
5866 LIST_FOR_EACH(e, &This->patches[i]) {
5867 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5868 if(patch->Handle == Handle) {
5869 TRACE("Deleting patch %p\n", patch);
5870 list_remove(&patch->entry);
5871 HeapFree(GetProcessHeap(), 0, patch->mem);
5872 HeapFree(GetProcessHeap(), 0, patch);
5877 /* TODO: Write a test for the return value */
5878 FIXME("Attempt to destroy nonexistent patch\n");
5879 return WINED3DERR_INVALIDCALL;
5882 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5884 IWineD3DSwapChain *swapchain;
5886 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5887 if (SUCCEEDED(hr)) {
5888 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5895 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5899 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5900 checkGLcall("glGenFramebuffersEXT()");
5902 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5903 checkGLcall("glBindFramebuffer()");
5906 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5907 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5908 IWineD3DBaseTextureImpl *texture_impl;
5909 GLenum texttarget, target;
5912 texttarget = surface_impl->glDescription.target;
5913 if(texttarget == GL_TEXTURE_2D) {
5914 target = GL_TEXTURE_2D;
5915 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
5916 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
5917 target = GL_TEXTURE_RECTANGLE_ARB;
5918 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
5920 target = GL_TEXTURE_CUBE_MAP_ARB;
5921 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
5924 IWineD3DSurface_PreLoad(surface);
5926 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
5927 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
5928 glBindTexture(target, old_binding);
5930 /* Update base texture states array */
5931 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
5932 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
5933 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
5934 if (texture_impl->baseTexture.bindCount) {
5935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
5938 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
5941 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
5942 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
5944 checkGLcall("attach_surface_fbo");
5947 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
5948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5949 IWineD3DSwapChain *swapchain;
5951 swapchain = get_swapchain(surface);
5955 TRACE("Surface %p is onscreen\n", surface);
5957 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5958 buffer = surface_get_gl_buffer(surface, swapchain);
5959 glDrawBuffer(buffer);
5960 checkGLcall("glDrawBuffer()");
5962 TRACE("Surface %p is offscreen\n", surface);
5963 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
5964 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
5968 glEnable(GL_SCISSOR_TEST);
5970 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
5972 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
5973 rect->x2 - rect->x1, rect->y2 - rect->y1);
5975 checkGLcall("glScissor");
5977 glDisable(GL_SCISSOR_TEST);
5979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
5981 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5982 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
5984 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
5985 glClear(GL_COLOR_BUFFER_BIT);
5986 checkGLcall("glClear");
5988 if (This->render_offscreen) {
5989 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
5991 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
5992 checkGLcall("glBindFramebuffer()");
5995 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
5996 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
5997 glDrawBuffer(GL_BACK);
5998 checkGLcall("glDrawBuffer()");
6002 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6003 unsigned int r, g, b, a;
6006 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6007 destfmt == WINED3DFMT_R8G8B8)
6010 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6012 a = (color & 0xff000000) >> 24;
6013 r = (color & 0x00ff0000) >> 16;
6014 g = (color & 0x0000ff00) >> 8;
6015 b = (color & 0x000000ff) >> 0;
6019 case WINED3DFMT_R5G6B5:
6020 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6027 TRACE("Returning %08x\n", ret);
6030 case WINED3DFMT_X1R5G5B5:
6031 case WINED3DFMT_A1R5G5B5:
6040 TRACE("Returning %08x\n", ret);
6044 TRACE("Returning %08x\n", a);
6047 case WINED3DFMT_X4R4G4B4:
6048 case WINED3DFMT_A4R4G4B4:
6057 TRACE("Returning %08x\n", ret);
6060 case WINED3DFMT_R3G3B2:
6067 TRACE("Returning %08x\n", ret);
6070 case WINED3DFMT_X8B8G8R8:
6071 case WINED3DFMT_A8B8G8R8:
6076 TRACE("Returning %08x\n", ret);
6079 case WINED3DFMT_A2R10G10B10:
6081 r = (r * 1024) / 256;
6082 g = (g * 1024) / 256;
6083 b = (b * 1024) / 256;
6088 TRACE("Returning %08x\n", ret);
6091 case WINED3DFMT_A2B10G10R10:
6093 r = (r * 1024) / 256;
6094 g = (g * 1024) / 256;
6095 b = (b * 1024) / 256;
6100 TRACE("Returning %08x\n", ret);
6104 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6109 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6111 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6113 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6115 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6116 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6117 return WINED3DERR_INVALIDCALL;
6120 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6121 color_fill_fbo(iface, pSurface, pRect, color);
6124 /* Just forward this to the DirectDraw blitting engine */
6125 memset(&BltFx, 0, sizeof(BltFx));
6126 BltFx.dwSize = sizeof(BltFx);
6127 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6128 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6132 /* rendertarget and depth stencil functions */
6133 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6136 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6137 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6138 return WINED3DERR_INVALIDCALL;
6141 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6142 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6143 /* Note inc ref on returned surface */
6144 if(*ppRenderTarget != NULL)
6145 IWineD3DSurface_AddRef(*ppRenderTarget);
6149 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6151 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6152 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6153 IWineD3DSwapChainImpl *Swapchain;
6156 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6158 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6159 if(hr != WINED3D_OK) {
6160 ERR("Can't get the swapchain\n");
6164 /* Make sure to release the swapchain */
6165 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6167 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6168 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6169 return WINED3DERR_INVALIDCALL;
6171 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6172 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6173 return WINED3DERR_INVALIDCALL;
6176 if(Swapchain->frontBuffer != Front) {
6177 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6179 if(Swapchain->frontBuffer)
6180 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6181 Swapchain->frontBuffer = Front;
6183 if(Swapchain->frontBuffer) {
6184 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6188 if(Back && !Swapchain->backBuffer) {
6189 /* We need memory for the back buffer array - only one back buffer this way */
6190 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6191 if(!Swapchain->backBuffer) {
6192 ERR("Out of memory\n");
6193 return E_OUTOFMEMORY;
6197 if(Swapchain->backBuffer[0] != Back) {
6198 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6200 /* What to do about the context here in the case of multithreading? Not sure.
6201 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6204 if(!Swapchain->backBuffer[0]) {
6205 /* GL was told to draw to the front buffer at creation,
6208 glDrawBuffer(GL_BACK);
6209 checkGLcall("glDrawBuffer(GL_BACK)");
6210 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6211 Swapchain->presentParms.BackBufferCount = 1;
6213 /* That makes problems - disable for now */
6214 /* glDrawBuffer(GL_FRONT); */
6215 checkGLcall("glDrawBuffer(GL_FRONT)");
6216 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6217 Swapchain->presentParms.BackBufferCount = 0;
6221 if(Swapchain->backBuffer[0])
6222 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6223 Swapchain->backBuffer[0] = Back;
6225 if(Swapchain->backBuffer[0]) {
6226 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6228 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6229 Swapchain->backBuffer = NULL;
6237 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6238 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6239 *ppZStencilSurface = This->stencilBufferTarget;
6240 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6242 if(*ppZStencilSurface != NULL) {
6243 /* Note inc ref on returned surface */
6244 IWineD3DSurface_AddRef(*ppZStencilSurface);
6247 return WINED3DERR_NOTFOUND;
6251 /* TODO: Handle stencil attachments */
6252 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6253 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6254 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6256 TRACE("Set depth stencil to %p\n", depth_stencil);
6258 if (depth_stencil_impl) {
6259 if (depth_stencil_impl->current_renderbuffer) {
6260 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6261 checkGLcall("glFramebufferRenderbufferEXT()");
6263 IWineD3DBaseTextureImpl *texture_impl;
6264 GLenum texttarget, target;
6265 GLint old_binding = 0;
6267 texttarget = depth_stencil_impl->glDescription.target;
6268 if(texttarget == GL_TEXTURE_2D) {
6269 target = GL_TEXTURE_2D;
6270 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6271 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6272 target = GL_TEXTURE_RECTANGLE_ARB;
6273 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6275 target = GL_TEXTURE_CUBE_MAP_ARB;
6276 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6279 IWineD3DSurface_PreLoad(depth_stencil);
6281 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6282 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6283 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6284 glBindTexture(target, old_binding);
6286 /* Update base texture states array */
6287 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6288 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6289 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6290 if (texture_impl->baseTexture.bindCount) {
6291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6294 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6297 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6298 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6299 checkGLcall("glFramebufferTexture2DEXT()");
6302 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6303 checkGLcall("glFramebufferTexture2DEXT()");
6307 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6309 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6311 TRACE("Set render target %u to %p\n", idx, render_target);
6314 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6315 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6317 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6318 checkGLcall("glFramebufferTexture2DEXT()");
6320 This->draw_buffers[idx] = GL_NONE;
6324 static void check_fbo_status(IWineD3DDevice *iface) {
6325 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6328 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6329 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6330 TRACE("FBO complete\n");
6332 IWineD3DSurfaceImpl *attachment;
6334 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6336 /* Dump the FBO attachments */
6337 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6338 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6340 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6341 attachment->pow2Width, attachment->pow2Height);
6344 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6346 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6347 attachment->pow2Width, attachment->pow2Height);
6352 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6353 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6354 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6355 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6357 if (!ds_impl) return FALSE;
6359 if (ds_impl->current_renderbuffer) {
6360 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6361 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6364 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6365 rt_impl->pow2Height != ds_impl->pow2Height);
6368 void apply_fbo_state(IWineD3DDevice *iface) {
6369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6372 if (This->render_offscreen) {
6373 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6375 /* Apply render targets */
6376 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6377 IWineD3DSurface *render_target = This->render_targets[i];
6378 if (This->fbo_color_attachments[i] != render_target) {
6379 set_render_target_fbo(iface, i, render_target);
6380 This->fbo_color_attachments[i] = render_target;
6384 /* Apply depth targets */
6385 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6386 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6387 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6389 if (This->stencilBufferTarget) {
6390 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6392 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6393 This->fbo_depth_attachment = This->stencilBufferTarget;
6396 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6397 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6398 checkGLcall("glDrawBuffers()");
6400 glDrawBuffer(This->draw_buffers[0]);
6401 checkGLcall("glDrawBuffer()");
6404 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6407 check_fbo_status(iface);
6410 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6411 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6413 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6414 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6417 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6418 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6419 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6420 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6423 case WINED3DTEXF_LINEAR:
6424 gl_filter = GL_LINEAR;
6428 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6429 case WINED3DTEXF_NONE:
6430 case WINED3DTEXF_POINT:
6431 gl_filter = GL_NEAREST;
6435 /* Attach src surface to src fbo */
6436 src_swapchain = get_swapchain(src_surface);
6437 if (src_swapchain) {
6440 TRACE("Source surface %p is onscreen\n", src_surface);
6441 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6442 /* Make sure the drawable is up to date. In the offscreen case
6443 * attach_surface_fbo() implicitly takes care of this. */
6444 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6447 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6448 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6449 glReadBuffer(buffer);
6450 checkGLcall("glReadBuffer()");
6452 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6453 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6455 TRACE("Source surface %p is offscreen\n", src_surface);
6457 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6458 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6459 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6460 checkGLcall("glReadBuffer()");
6464 /* Attach dst surface to dst fbo */
6465 dst_swapchain = get_swapchain(dst_surface);
6466 if (dst_swapchain) {
6469 TRACE("Destination surface %p is onscreen\n", dst_surface);
6470 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6471 /* Make sure the drawable is up to date. In the offscreen case
6472 * attach_surface_fbo() implicitly takes care of this. */
6473 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6476 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6477 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6478 glDrawBuffer(buffer);
6479 checkGLcall("glDrawBuffer()");
6481 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6482 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6484 TRACE("Destination surface %p is offscreen\n", dst_surface);
6486 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6487 if(!src_swapchain) {
6488 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6492 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6493 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6494 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6495 checkGLcall("glDrawBuffer()");
6497 glDisable(GL_SCISSOR_TEST);
6498 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6501 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6502 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6503 checkGLcall("glBlitFramebuffer()");
6505 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6506 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6507 checkGLcall("glBlitFramebuffer()");
6510 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6512 if (This->render_offscreen) {
6513 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6515 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6516 checkGLcall("glBindFramebuffer()");
6519 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6520 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6521 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6522 glDrawBuffer(GL_BACK);
6523 checkGLcall("glDrawBuffer()");
6528 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6530 WINED3DVIEWPORT viewport;
6532 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6534 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6535 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6536 This, RenderTargetIndex, GL_LIMITS(buffers));
6537 return WINED3DERR_INVALIDCALL;
6540 /* MSDN says that null disables the render target
6541 but a device must always be associated with a render target
6542 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6544 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6545 FIXME("Trying to set render target 0 to NULL\n");
6546 return WINED3DERR_INVALIDCALL;
6548 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6549 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);
6550 return WINED3DERR_INVALIDCALL;
6553 /* If we are trying to set what we already have, don't bother */
6554 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6555 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6558 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6559 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6560 This->render_targets[RenderTargetIndex] = pRenderTarget;
6562 /* Render target 0 is special */
6563 if(RenderTargetIndex == 0) {
6564 /* Finally, reset the viewport as the MSDN states. */
6565 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6566 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6569 viewport.MaxZ = 1.0f;
6570 viewport.MinZ = 0.0f;
6571 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6572 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6573 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6575 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6577 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6579 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6580 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6582 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6587 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6589 HRESULT hr = WINED3D_OK;
6590 IWineD3DSurface *tmp;
6592 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6594 if (pNewZStencil == This->stencilBufferTarget) {
6595 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6597 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6598 * depending on the renter target implementation being used.
6599 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6600 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6601 * stencil buffer and incur an extra memory overhead
6602 ******************************************************/
6604 tmp = This->stencilBufferTarget;
6605 This->stencilBufferTarget = pNewZStencil;
6606 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6607 /* should we be calling the parent or the wined3d surface? */
6608 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6609 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6612 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6613 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6623 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6624 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6626 /* TODO: the use of Impl is deprecated. */
6627 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6628 WINED3DLOCKED_RECT lockedRect;
6630 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6632 /* some basic validation checks */
6633 if(This->cursorTexture) {
6634 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6636 glDeleteTextures(1, &This->cursorTexture);
6638 This->cursorTexture = 0;
6641 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6642 This->haveHardwareCursor = TRUE;
6644 This->haveHardwareCursor = FALSE;
6647 WINED3DLOCKED_RECT rect;
6649 /* MSDN: Cursor must be A8R8G8B8 */
6650 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6651 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6652 return WINED3DERR_INVALIDCALL;
6655 /* MSDN: Cursor must be smaller than the display mode */
6656 if(pSur->currentDesc.Width > This->ddraw_width ||
6657 pSur->currentDesc.Height > This->ddraw_height) {
6658 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);
6659 return WINED3DERR_INVALIDCALL;
6662 if (!This->haveHardwareCursor) {
6663 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6665 /* Do not store the surface's pointer because the application may
6666 * release it after setting the cursor image. Windows doesn't
6667 * addref the set surface, so we can't do this either without
6668 * creating circular refcount dependencies. Copy out the gl texture
6671 This->cursorWidth = pSur->currentDesc.Width;
6672 This->cursorHeight = pSur->currentDesc.Height;
6673 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6675 const GlPixelFormatDesc *glDesc;
6676 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6677 char *mem, *bits = (char *)rect.pBits;
6678 GLint intfmt = glDesc->glInternal;
6679 GLint format = glDesc->glFormat;
6680 GLint type = glDesc->glType;
6681 INT height = This->cursorHeight;
6682 INT width = This->cursorWidth;
6683 INT bpp = tableEntry->bpp;
6686 /* Reformat the texture memory (pitch and width can be
6688 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6689 for(i = 0; i < height; i++)
6690 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6691 IWineD3DSurface_UnlockRect(pCursorBitmap);
6694 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6695 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6696 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6699 /* Make sure that a proper texture unit is selected */
6700 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6701 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6702 checkGLcall("glActiveTextureARB");
6704 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6705 /* Create a new cursor texture */
6706 glGenTextures(1, &This->cursorTexture);
6707 checkGLcall("glGenTextures");
6708 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6709 checkGLcall("glBindTexture");
6710 /* Copy the bitmap memory into the cursor texture */
6711 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6712 HeapFree(GetProcessHeap(), 0, mem);
6713 checkGLcall("glTexImage2D");
6715 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6716 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6717 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6724 FIXME("A cursor texture was not returned.\n");
6725 This->cursorTexture = 0;
6730 /* Draw a hardware cursor */
6731 ICONINFO cursorInfo;
6733 /* Create and clear maskBits because it is not needed for
6734 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6736 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6737 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6738 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6739 WINED3DLOCK_NO_DIRTY_UPDATE |
6740 WINED3DLOCK_READONLY
6742 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6743 pSur->currentDesc.Height);
6745 cursorInfo.fIcon = FALSE;
6746 cursorInfo.xHotspot = XHotSpot;
6747 cursorInfo.yHotspot = YHotSpot;
6748 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6749 pSur->currentDesc.Height, 1,
6751 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6752 pSur->currentDesc.Height, 1,
6753 32, lockedRect.pBits);
6754 IWineD3DSurface_UnlockRect(pCursorBitmap);
6755 /* Create our cursor and clean up. */
6756 cursor = CreateIconIndirect(&cursorInfo);
6758 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6759 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6760 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6761 This->hardwareCursor = cursor;
6762 HeapFree(GetProcessHeap(), 0, maskBits);
6766 This->xHotSpot = XHotSpot;
6767 This->yHotSpot = YHotSpot;
6771 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6773 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6775 This->xScreenSpace = XScreenSpace;
6776 This->yScreenSpace = YScreenSpace;
6782 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6784 BOOL oldVisible = This->bCursorVisible;
6787 TRACE("(%p) : visible(%d)\n", This, bShow);
6790 * When ShowCursor is first called it should make the cursor appear at the OS's last
6791 * known cursor position. Because of this, some applications just repetitively call
6792 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6795 This->xScreenSpace = pt.x;
6796 This->yScreenSpace = pt.y;
6798 if (This->haveHardwareCursor) {
6799 This->bCursorVisible = bShow;
6801 SetCursor(This->hardwareCursor);
6807 if (This->cursorTexture)
6808 This->bCursorVisible = bShow;
6814 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6816 IWineD3DResourceImpl *resource;
6817 TRACE("(%p) : state (%u)\n", This, This->state);
6819 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6820 switch (This->state) {
6823 case WINED3DERR_DEVICELOST:
6825 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6826 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6827 return WINED3DERR_DEVICENOTRESET;
6829 return WINED3DERR_DEVICELOST;
6831 case WINED3DERR_DRIVERINTERNALERROR:
6832 return WINED3DERR_DRIVERINTERNALERROR;
6836 return WINED3DERR_DRIVERINTERNALERROR;
6840 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6841 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6842 /** FIXME: Resource tracking needs to be done,
6843 * The closes we can do to this is set the priorities of all managed textures low
6844 * and then reset them.
6845 ***********************************************************/
6846 FIXME("(%p) : stub\n", This);
6850 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6851 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6853 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6854 if(surface->Flags & SFLAG_DIBSECTION) {
6855 /* Release the DC */
6856 SelectObject(surface->hDC, surface->dib.holdbitmap);
6857 DeleteDC(surface->hDC);
6858 /* Release the DIB section */
6859 DeleteObject(surface->dib.DIBsection);
6860 surface->dib.bitmap_data = NULL;
6861 surface->resource.allocatedMemory = NULL;
6862 surface->Flags &= ~SFLAG_DIBSECTION;
6864 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6865 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6866 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6867 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6868 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6870 surface->pow2Width = surface->pow2Height = 1;
6871 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6872 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6874 surface->glRect.left = 0;
6875 surface->glRect.top = 0;
6876 surface->glRect.right = surface->pow2Width;
6877 surface->glRect.bottom = surface->pow2Height;
6879 if(surface->glDescription.textureName) {
6880 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6882 glDeleteTextures(1, &surface->glDescription.textureName);
6884 surface->glDescription.textureName = 0;
6885 surface->Flags &= ~SFLAG_CLIENT;
6887 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6888 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6889 surface->Flags |= SFLAG_NONPOW2;
6891 surface->Flags &= ~SFLAG_NONPOW2;
6893 HeapFree(GetProcessHeap(), 0, surface->resource.allocatedMemory);
6894 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6897 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6898 TRACE("Unloading resource %p\n", resource);
6899 IWineD3DResource_UnLoad(resource);
6900 IWineD3DResource_Release(resource);
6904 static void reset_fbo_state(IWineD3DDevice *iface) {
6905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6909 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6910 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
6913 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
6916 if (This->src_fbo) {
6917 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
6920 if (This->dst_fbo) {
6921 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
6924 checkGLcall("Tear down fbos\n");
6927 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6928 This->fbo_color_attachments[i] = NULL;
6930 This->fbo_depth_attachment = NULL;
6933 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
6935 WINED3DDISPLAYMODE m;
6938 /* All Windowed modes are supported, as is leaving the current mode */
6939 if(pp->Windowed) return TRUE;
6940 if(!pp->BackBufferWidth) return TRUE;
6941 if(!pp->BackBufferHeight) return TRUE;
6943 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6944 for(i = 0; i < count; i++) {
6945 memset(&m, 0, sizeof(m));
6946 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6948 ERR("EnumAdapterModes failed\n");
6950 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6951 /* Mode found, it is supported */
6955 /* Mode not found -> not supported */
6959 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6961 IWineD3DSwapChainImpl *swapchain;
6963 BOOL DisplayModeChanged = FALSE;
6964 WINED3DDISPLAYMODE mode;
6965 IWineD3DBaseShaderImpl *shader;
6966 IWineD3DSurfaceImpl *target;
6968 TRACE("(%p)\n", This);
6970 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6972 ERR("Failed to get the first implicit swapchain\n");
6976 if(!is_display_mode_supported(This, pPresentationParameters)) {
6977 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
6978 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
6979 pPresentationParameters->BackBufferHeight);
6980 return WINED3DERR_INVALIDCALL;
6983 /* Is it necessary to recreate the gl context? Actually every setting can be changed
6984 * on an existing gl context, so there's no real need for recreation.
6986 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
6988 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
6990 TRACE("New params:\n");
6991 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
6992 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
6993 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
6994 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
6995 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
6996 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
6997 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
6998 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
6999 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7000 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7001 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7002 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7003 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7005 /* No special treatment of these parameters. Just store them */
7006 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7007 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7008 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7009 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7011 /* What to do about these? */
7012 if(pPresentationParameters->BackBufferCount != 0 &&
7013 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7014 ERR("Cannot change the back buffer count yet\n");
7016 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7017 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7018 ERR("Cannot change the back buffer format yet\n");
7020 if(pPresentationParameters->hDeviceWindow != NULL &&
7021 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7022 ERR("Cannot change the device window yet\n");
7024 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7025 ERR("What do do about a changed auto depth stencil parameter?\n");
7028 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7029 reset_fbo_state((IWineD3DDevice *) This);
7032 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7033 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7034 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7038 if(This->depth_blt_texture) {
7039 glDeleteTextures(1, &This->depth_blt_texture);
7040 This->depth_blt_texture = 0;
7042 This->shader_backend->shader_destroy_depth_blt(iface);
7043 This->shader_backend->shader_free_private(iface);
7045 for (i = 0; i < GL_LIMITS(textures); i++) {
7046 /* Textures are recreated below */
7047 glDeleteTextures(1, &This->dummyTextureName[i]);
7048 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7049 This->dummyTextureName[i] = 0;
7053 while(This->numContexts) {
7054 DestroyContext(This, This->contexts[0]);
7056 This->activeContext = NULL;
7057 HeapFree(GetProcessHeap(), 0, swapchain->context);
7058 swapchain->context = NULL;
7059 swapchain->num_contexts = 0;
7061 if(pPresentationParameters->Windowed) {
7062 mode.Width = swapchain->orig_width;
7063 mode.Height = swapchain->orig_height;
7064 mode.RefreshRate = 0;
7065 mode.Format = swapchain->presentParms.BackBufferFormat;
7067 mode.Width = pPresentationParameters->BackBufferWidth;
7068 mode.Height = pPresentationParameters->BackBufferHeight;
7069 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7070 mode.Format = swapchain->presentParms.BackBufferFormat;
7073 /* Should Width == 800 && Height == 0 set 800x600? */
7074 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7075 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7076 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7083 vp.Width = pPresentationParameters->BackBufferWidth;
7084 vp.Height = pPresentationParameters->BackBufferHeight;
7088 if(!pPresentationParameters->Windowed) {
7089 DisplayModeChanged = TRUE;
7091 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7092 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7094 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7095 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7096 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7098 if(This->auto_depth_stencil_buffer) {
7099 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7103 /* Now set the new viewport */
7104 IWineD3DDevice_SetViewport(iface, &vp);
7107 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7108 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7109 DisplayModeChanged) {
7111 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7112 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7113 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7114 } else if(!pPresentationParameters->Windowed) {
7115 DWORD style = This->style, exStyle = This->exStyle;
7116 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7117 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7118 * Reset to clear up their mess. Guild Wars also loses the device during that.
7122 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7123 This->style = style;
7124 This->exStyle = exStyle;
7127 /* Recreate the primary swapchain's context */
7128 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7129 if(swapchain->backBuffer) {
7130 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7132 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7134 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7135 &swapchain->presentParms);
7136 swapchain->num_contexts = 1;
7137 This->activeContext = swapchain->context[0];
7138 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7140 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7142 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7144 create_dummy_textures(This);
7147 hr = This->shader_backend->shader_alloc_private(iface);
7149 ERR("Failed to recreate shader private data\n");
7153 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7159 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7161 /** FIXME: always true at the moment **/
7162 if(!bEnableDialogs) {
7163 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7169 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7171 TRACE("(%p) : pParameters %p\n", This, pParameters);
7173 *pParameters = This->createParms;
7177 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7178 IWineD3DSwapChain *swapchain;
7179 HRESULT hrc = WINED3D_OK;
7181 TRACE("Relaying to swapchain\n");
7183 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7184 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7185 IWineD3DSwapChain_Release(swapchain);
7190 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7191 IWineD3DSwapChain *swapchain;
7192 HRESULT hrc = WINED3D_OK;
7194 TRACE("Relaying to swapchain\n");
7196 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7197 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7198 IWineD3DSwapChain_Release(swapchain);
7204 /** ********************************************************
7205 * Notification functions
7206 ** ********************************************************/
7207 /** This function must be called in the release of a resource when ref == 0,
7208 * the contents of resource must still be correct,
7209 * any handles to other resource held by the caller must be closed
7210 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7211 *****************************************************/
7212 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7215 TRACE("(%p) : Adding Resource %p\n", This, resource);
7216 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7219 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7222 TRACE("(%p) : Removing resource %p\n", This, resource);
7224 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7228 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7232 TRACE("(%p) : resource %p\n", This, resource);
7233 switch(IWineD3DResource_GetType(resource)){
7234 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7235 case WINED3DRTYPE_SURFACE: {
7238 /* Cleanup any FBO attachments if d3d is enabled */
7239 if(This->d3d_initialized) {
7240 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7241 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7243 TRACE("Last active render target destroyed\n");
7244 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7245 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7246 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7247 * and the lastActiveRenderTarget member shouldn't matter
7250 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7251 TRACE("Activating primary back buffer\n");
7252 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7253 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7254 /* Single buffering environment */
7255 TRACE("Activating primary front buffer\n");
7256 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7258 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7259 /* Implicit render target destroyed, that means the device is being destroyed
7260 * whatever we set here, it shouldn't matter
7262 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7265 /* May happen during ddraw uninitialization */
7266 TRACE("Render target set, but swapchain does not exist!\n");
7267 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7271 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7272 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7273 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7274 set_render_target_fbo(iface, i, NULL);
7275 This->fbo_color_attachments[i] = NULL;
7278 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7279 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7280 set_depth_stencil_fbo(iface, NULL);
7281 This->fbo_depth_attachment = NULL;
7287 case WINED3DRTYPE_TEXTURE:
7288 case WINED3DRTYPE_CUBETEXTURE:
7289 case WINED3DRTYPE_VOLUMETEXTURE:
7290 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7291 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7292 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7293 This->stateBlock->textures[counter] = NULL;
7295 if (This->updateStateBlock != This->stateBlock ){
7296 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7297 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7298 This->updateStateBlock->textures[counter] = NULL;
7303 case WINED3DRTYPE_VOLUME:
7304 /* TODO: nothing really? */
7306 case WINED3DRTYPE_VERTEXBUFFER:
7307 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7310 TRACE("Cleaning up stream pointers\n");
7312 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7313 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7314 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7316 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7317 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7318 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7319 This->updateStateBlock->streamSource[streamNumber] = 0;
7320 /* Set changed flag? */
7323 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) */
7324 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7325 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7326 This->stateBlock->streamSource[streamNumber] = 0;
7329 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7330 else { /* This shouldn't happen */
7331 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7338 case WINED3DRTYPE_INDEXBUFFER:
7339 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7340 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7341 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7342 This->updateStateBlock->pIndexData = NULL;
7345 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7346 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7347 This->stateBlock->pIndexData = NULL;
7353 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7358 /* Remove the resource from the resourceStore */
7359 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7361 TRACE("Resource released\n");
7365 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7367 IWineD3DResourceImpl *resource, *cursor;
7369 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7371 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7372 TRACE("enumerating resource %p\n", resource);
7373 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7374 ret = pCallback((IWineD3DResource *) resource, pData);
7375 if(ret == S_FALSE) {
7376 TRACE("Canceling enumeration\n");
7383 /**********************************************************
7384 * IWineD3DDevice VTbl follows
7385 **********************************************************/
7387 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7389 /*** IUnknown methods ***/
7390 IWineD3DDeviceImpl_QueryInterface,
7391 IWineD3DDeviceImpl_AddRef,
7392 IWineD3DDeviceImpl_Release,
7393 /*** IWineD3DDevice methods ***/
7394 IWineD3DDeviceImpl_GetParent,
7395 /*** Creation methods**/
7396 IWineD3DDeviceImpl_CreateVertexBuffer,
7397 IWineD3DDeviceImpl_CreateIndexBuffer,
7398 IWineD3DDeviceImpl_CreateStateBlock,
7399 IWineD3DDeviceImpl_CreateSurface,
7400 IWineD3DDeviceImpl_CreateTexture,
7401 IWineD3DDeviceImpl_CreateVolumeTexture,
7402 IWineD3DDeviceImpl_CreateVolume,
7403 IWineD3DDeviceImpl_CreateCubeTexture,
7404 IWineD3DDeviceImpl_CreateQuery,
7405 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7406 IWineD3DDeviceImpl_CreateVertexDeclaration,
7407 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7408 IWineD3DDeviceImpl_CreateVertexShader,
7409 IWineD3DDeviceImpl_CreatePixelShader,
7410 IWineD3DDeviceImpl_CreatePalette,
7411 /*** Odd functions **/
7412 IWineD3DDeviceImpl_Init3D,
7413 IWineD3DDeviceImpl_Uninit3D,
7414 IWineD3DDeviceImpl_SetFullscreen,
7415 IWineD3DDeviceImpl_SetMultithreaded,
7416 IWineD3DDeviceImpl_EvictManagedResources,
7417 IWineD3DDeviceImpl_GetAvailableTextureMem,
7418 IWineD3DDeviceImpl_GetBackBuffer,
7419 IWineD3DDeviceImpl_GetCreationParameters,
7420 IWineD3DDeviceImpl_GetDeviceCaps,
7421 IWineD3DDeviceImpl_GetDirect3D,
7422 IWineD3DDeviceImpl_GetDisplayMode,
7423 IWineD3DDeviceImpl_SetDisplayMode,
7424 IWineD3DDeviceImpl_GetHWND,
7425 IWineD3DDeviceImpl_SetHWND,
7426 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7427 IWineD3DDeviceImpl_GetRasterStatus,
7428 IWineD3DDeviceImpl_GetSwapChain,
7429 IWineD3DDeviceImpl_Reset,
7430 IWineD3DDeviceImpl_SetDialogBoxMode,
7431 IWineD3DDeviceImpl_SetCursorProperties,
7432 IWineD3DDeviceImpl_SetCursorPosition,
7433 IWineD3DDeviceImpl_ShowCursor,
7434 IWineD3DDeviceImpl_TestCooperativeLevel,
7435 /*** Getters and setters **/
7436 IWineD3DDeviceImpl_SetClipPlane,
7437 IWineD3DDeviceImpl_GetClipPlane,
7438 IWineD3DDeviceImpl_SetClipStatus,
7439 IWineD3DDeviceImpl_GetClipStatus,
7440 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7441 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7442 IWineD3DDeviceImpl_SetDepthStencilSurface,
7443 IWineD3DDeviceImpl_GetDepthStencilSurface,
7444 IWineD3DDeviceImpl_SetFVF,
7445 IWineD3DDeviceImpl_GetFVF,
7446 IWineD3DDeviceImpl_SetGammaRamp,
7447 IWineD3DDeviceImpl_GetGammaRamp,
7448 IWineD3DDeviceImpl_SetIndices,
7449 IWineD3DDeviceImpl_GetIndices,
7450 IWineD3DDeviceImpl_SetBaseVertexIndex,
7451 IWineD3DDeviceImpl_GetBaseVertexIndex,
7452 IWineD3DDeviceImpl_SetLight,
7453 IWineD3DDeviceImpl_GetLight,
7454 IWineD3DDeviceImpl_SetLightEnable,
7455 IWineD3DDeviceImpl_GetLightEnable,
7456 IWineD3DDeviceImpl_SetMaterial,
7457 IWineD3DDeviceImpl_GetMaterial,
7458 IWineD3DDeviceImpl_SetNPatchMode,
7459 IWineD3DDeviceImpl_GetNPatchMode,
7460 IWineD3DDeviceImpl_SetPaletteEntries,
7461 IWineD3DDeviceImpl_GetPaletteEntries,
7462 IWineD3DDeviceImpl_SetPixelShader,
7463 IWineD3DDeviceImpl_GetPixelShader,
7464 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7465 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7466 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7467 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7468 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7469 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7470 IWineD3DDeviceImpl_SetRenderState,
7471 IWineD3DDeviceImpl_GetRenderState,
7472 IWineD3DDeviceImpl_SetRenderTarget,
7473 IWineD3DDeviceImpl_GetRenderTarget,
7474 IWineD3DDeviceImpl_SetFrontBackBuffers,
7475 IWineD3DDeviceImpl_SetSamplerState,
7476 IWineD3DDeviceImpl_GetSamplerState,
7477 IWineD3DDeviceImpl_SetScissorRect,
7478 IWineD3DDeviceImpl_GetScissorRect,
7479 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7480 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7481 IWineD3DDeviceImpl_SetStreamSource,
7482 IWineD3DDeviceImpl_GetStreamSource,
7483 IWineD3DDeviceImpl_SetStreamSourceFreq,
7484 IWineD3DDeviceImpl_GetStreamSourceFreq,
7485 IWineD3DDeviceImpl_SetTexture,
7486 IWineD3DDeviceImpl_GetTexture,
7487 IWineD3DDeviceImpl_SetTextureStageState,
7488 IWineD3DDeviceImpl_GetTextureStageState,
7489 IWineD3DDeviceImpl_SetTransform,
7490 IWineD3DDeviceImpl_GetTransform,
7491 IWineD3DDeviceImpl_SetVertexDeclaration,
7492 IWineD3DDeviceImpl_GetVertexDeclaration,
7493 IWineD3DDeviceImpl_SetVertexShader,
7494 IWineD3DDeviceImpl_GetVertexShader,
7495 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7496 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7497 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7498 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7499 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7500 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7501 IWineD3DDeviceImpl_SetViewport,
7502 IWineD3DDeviceImpl_GetViewport,
7503 IWineD3DDeviceImpl_MultiplyTransform,
7504 IWineD3DDeviceImpl_ValidateDevice,
7505 IWineD3DDeviceImpl_ProcessVertices,
7506 /*** State block ***/
7507 IWineD3DDeviceImpl_BeginStateBlock,
7508 IWineD3DDeviceImpl_EndStateBlock,
7509 /*** Scene management ***/
7510 IWineD3DDeviceImpl_BeginScene,
7511 IWineD3DDeviceImpl_EndScene,
7512 IWineD3DDeviceImpl_Present,
7513 IWineD3DDeviceImpl_Clear,
7515 IWineD3DDeviceImpl_DrawPrimitive,
7516 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7517 IWineD3DDeviceImpl_DrawPrimitiveUP,
7518 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7519 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7520 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7521 IWineD3DDeviceImpl_DrawRectPatch,
7522 IWineD3DDeviceImpl_DrawTriPatch,
7523 IWineD3DDeviceImpl_DeletePatch,
7524 IWineD3DDeviceImpl_ColorFill,
7525 IWineD3DDeviceImpl_UpdateTexture,
7526 IWineD3DDeviceImpl_UpdateSurface,
7527 IWineD3DDeviceImpl_GetFrontBufferData,
7528 /*** object tracking ***/
7529 IWineD3DDeviceImpl_ResourceReleased,
7530 IWineD3DDeviceImpl_EnumResources
7533 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7535 /*** IUnknown methods ***/
7536 IWineD3DDeviceImpl_QueryInterface,
7537 IWineD3DDeviceImpl_AddRef,
7538 IWineD3DDeviceImpl_Release,
7539 /*** IWineD3DDevice methods ***/
7540 IWineD3DDeviceImpl_GetParent,
7541 /*** Creation methods**/
7542 IWineD3DDeviceImpl_CreateVertexBuffer,
7543 IWineD3DDeviceImpl_CreateIndexBuffer,
7544 IWineD3DDeviceImpl_CreateStateBlock,
7545 IWineD3DDeviceImpl_CreateSurface,
7546 IWineD3DDeviceImpl_CreateTexture,
7547 IWineD3DDeviceImpl_CreateVolumeTexture,
7548 IWineD3DDeviceImpl_CreateVolume,
7549 IWineD3DDeviceImpl_CreateCubeTexture,
7550 IWineD3DDeviceImpl_CreateQuery,
7551 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7552 IWineD3DDeviceImpl_CreateVertexDeclaration,
7553 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7554 IWineD3DDeviceImpl_CreateVertexShader,
7555 IWineD3DDeviceImpl_CreatePixelShader,
7556 IWineD3DDeviceImpl_CreatePalette,
7557 /*** Odd functions **/
7558 IWineD3DDeviceImpl_Init3D,
7559 IWineD3DDeviceImpl_Uninit3D,
7560 IWineD3DDeviceImpl_SetFullscreen,
7561 IWineD3DDeviceImpl_SetMultithreaded,
7562 IWineD3DDeviceImpl_EvictManagedResources,
7563 IWineD3DDeviceImpl_GetAvailableTextureMem,
7564 IWineD3DDeviceImpl_GetBackBuffer,
7565 IWineD3DDeviceImpl_GetCreationParameters,
7566 IWineD3DDeviceImpl_GetDeviceCaps,
7567 IWineD3DDeviceImpl_GetDirect3D,
7568 IWineD3DDeviceImpl_GetDisplayMode,
7569 IWineD3DDeviceImpl_SetDisplayMode,
7570 IWineD3DDeviceImpl_GetHWND,
7571 IWineD3DDeviceImpl_SetHWND,
7572 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7573 IWineD3DDeviceImpl_GetRasterStatus,
7574 IWineD3DDeviceImpl_GetSwapChain,
7575 IWineD3DDeviceImpl_Reset,
7576 IWineD3DDeviceImpl_SetDialogBoxMode,
7577 IWineD3DDeviceImpl_SetCursorProperties,
7578 IWineD3DDeviceImpl_SetCursorPosition,
7579 IWineD3DDeviceImpl_ShowCursor,
7580 IWineD3DDeviceImpl_TestCooperativeLevel,
7581 /*** Getters and setters **/
7582 IWineD3DDeviceImpl_SetClipPlane,
7583 IWineD3DDeviceImpl_GetClipPlane,
7584 IWineD3DDeviceImpl_SetClipStatus,
7585 IWineD3DDeviceImpl_GetClipStatus,
7586 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7587 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7588 IWineD3DDeviceImpl_SetDepthStencilSurface,
7589 IWineD3DDeviceImpl_GetDepthStencilSurface,
7590 IWineD3DDeviceImpl_SetFVF,
7591 IWineD3DDeviceImpl_GetFVF,
7592 IWineD3DDeviceImpl_SetGammaRamp,
7593 IWineD3DDeviceImpl_GetGammaRamp,
7594 IWineD3DDeviceImpl_SetIndices,
7595 IWineD3DDeviceImpl_GetIndices,
7596 IWineD3DDeviceImpl_SetBaseVertexIndex,
7597 IWineD3DDeviceImpl_GetBaseVertexIndex,
7598 IWineD3DDeviceImpl_SetLight,
7599 IWineD3DDeviceImpl_GetLight,
7600 IWineD3DDeviceImpl_SetLightEnable,
7601 IWineD3DDeviceImpl_GetLightEnable,
7602 IWineD3DDeviceImpl_SetMaterial,
7603 IWineD3DDeviceImpl_GetMaterial,
7604 IWineD3DDeviceImpl_SetNPatchMode,
7605 IWineD3DDeviceImpl_GetNPatchMode,
7606 IWineD3DDeviceImpl_SetPaletteEntries,
7607 IWineD3DDeviceImpl_GetPaletteEntries,
7608 IWineD3DDeviceImpl_SetPixelShader,
7609 IWineD3DDeviceImpl_GetPixelShader,
7610 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7611 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7612 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7613 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7614 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7615 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7616 IWineD3DDeviceImpl_SetRenderState,
7617 IWineD3DDeviceImpl_GetRenderState,
7618 IWineD3DDeviceImpl_SetRenderTarget,
7619 IWineD3DDeviceImpl_GetRenderTarget,
7620 IWineD3DDeviceImpl_SetFrontBackBuffers,
7621 IWineD3DDeviceImpl_SetSamplerState,
7622 IWineD3DDeviceImpl_GetSamplerState,
7623 IWineD3DDeviceImpl_SetScissorRect,
7624 IWineD3DDeviceImpl_GetScissorRect,
7625 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7626 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7627 IWineD3DDeviceImpl_SetStreamSource,
7628 IWineD3DDeviceImpl_GetStreamSource,
7629 IWineD3DDeviceImpl_SetStreamSourceFreq,
7630 IWineD3DDeviceImpl_GetStreamSourceFreq,
7631 IWineD3DDeviceImpl_SetTexture,
7632 IWineD3DDeviceImpl_GetTexture,
7633 IWineD3DDeviceImpl_SetTextureStageState,
7634 IWineD3DDeviceImpl_GetTextureStageState,
7635 IWineD3DDeviceImpl_SetTransform,
7636 IWineD3DDeviceImpl_GetTransform,
7637 IWineD3DDeviceImpl_SetVertexDeclaration,
7638 IWineD3DDeviceImpl_GetVertexDeclaration,
7639 IWineD3DDeviceImpl_SetVertexShader,
7640 IWineD3DDeviceImpl_GetVertexShader,
7641 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7642 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7643 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7644 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7645 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7646 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7647 IWineD3DDeviceImpl_SetViewport,
7648 IWineD3DDeviceImpl_GetViewport,
7649 IWineD3DDeviceImpl_MultiplyTransform,
7650 IWineD3DDeviceImpl_ValidateDevice,
7651 IWineD3DDeviceImpl_ProcessVertices,
7652 /*** State block ***/
7653 IWineD3DDeviceImpl_BeginStateBlock,
7654 IWineD3DDeviceImpl_EndStateBlock,
7655 /*** Scene management ***/
7656 IWineD3DDeviceImpl_BeginScene,
7657 IWineD3DDeviceImpl_EndScene,
7658 IWineD3DDeviceImpl_Present,
7659 IWineD3DDeviceImpl_Clear,
7661 IWineD3DDeviceImpl_DrawPrimitive,
7662 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7663 IWineD3DDeviceImpl_DrawPrimitiveUP,
7664 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7665 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7666 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7667 IWineD3DDeviceImpl_DrawRectPatch,
7668 IWineD3DDeviceImpl_DrawTriPatch,
7669 IWineD3DDeviceImpl_DeletePatch,
7670 IWineD3DDeviceImpl_ColorFill,
7671 IWineD3DDeviceImpl_UpdateTexture,
7672 IWineD3DDeviceImpl_UpdateSurface,
7673 IWineD3DDeviceImpl_GetFrontBufferData,
7674 /*** object tracking ***/
7675 IWineD3DDeviceImpl_ResourceReleased,
7676 IWineD3DDeviceImpl_EnumResources
7679 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7680 WINED3DRS_ALPHABLENDENABLE ,
7681 WINED3DRS_ALPHAFUNC ,
7682 WINED3DRS_ALPHAREF ,
7683 WINED3DRS_ALPHATESTENABLE ,
7685 WINED3DRS_COLORWRITEENABLE ,
7686 WINED3DRS_DESTBLEND ,
7687 WINED3DRS_DITHERENABLE ,
7688 WINED3DRS_FILLMODE ,
7689 WINED3DRS_FOGDENSITY ,
7691 WINED3DRS_FOGSTART ,
7692 WINED3DRS_LASTPIXEL ,
7693 WINED3DRS_SHADEMODE ,
7694 WINED3DRS_SRCBLEND ,
7695 WINED3DRS_STENCILENABLE ,
7696 WINED3DRS_STENCILFAIL ,
7697 WINED3DRS_STENCILFUNC ,
7698 WINED3DRS_STENCILMASK ,
7699 WINED3DRS_STENCILPASS ,
7700 WINED3DRS_STENCILREF ,
7701 WINED3DRS_STENCILWRITEMASK ,
7702 WINED3DRS_STENCILZFAIL ,
7703 WINED3DRS_TEXTUREFACTOR ,
7714 WINED3DRS_ZWRITEENABLE
7717 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7718 WINED3DTSS_ADDRESSW ,
7719 WINED3DTSS_ALPHAARG0 ,
7720 WINED3DTSS_ALPHAARG1 ,
7721 WINED3DTSS_ALPHAARG2 ,
7722 WINED3DTSS_ALPHAOP ,
7723 WINED3DTSS_BUMPENVLOFFSET ,
7724 WINED3DTSS_BUMPENVLSCALE ,
7725 WINED3DTSS_BUMPENVMAT00 ,
7726 WINED3DTSS_BUMPENVMAT01 ,
7727 WINED3DTSS_BUMPENVMAT10 ,
7728 WINED3DTSS_BUMPENVMAT11 ,
7729 WINED3DTSS_COLORARG0 ,
7730 WINED3DTSS_COLORARG1 ,
7731 WINED3DTSS_COLORARG2 ,
7732 WINED3DTSS_COLOROP ,
7733 WINED3DTSS_RESULTARG ,
7734 WINED3DTSS_TEXCOORDINDEX ,
7735 WINED3DTSS_TEXTURETRANSFORMFLAGS
7738 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7739 WINED3DSAMP_ADDRESSU ,
7740 WINED3DSAMP_ADDRESSV ,
7741 WINED3DSAMP_ADDRESSW ,
7742 WINED3DSAMP_BORDERCOLOR ,
7743 WINED3DSAMP_MAGFILTER ,
7744 WINED3DSAMP_MINFILTER ,
7745 WINED3DSAMP_MIPFILTER ,
7746 WINED3DSAMP_MIPMAPLODBIAS ,
7747 WINED3DSAMP_MAXMIPLEVEL ,
7748 WINED3DSAMP_MAXANISOTROPY ,
7749 WINED3DSAMP_SRGBTEXTURE ,
7750 WINED3DSAMP_ELEMENTINDEX
7753 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7755 WINED3DRS_AMBIENTMATERIALSOURCE ,
7756 WINED3DRS_CLIPPING ,
7757 WINED3DRS_CLIPPLANEENABLE ,
7758 WINED3DRS_COLORVERTEX ,
7759 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7760 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7761 WINED3DRS_FOGDENSITY ,
7763 WINED3DRS_FOGSTART ,
7764 WINED3DRS_FOGTABLEMODE ,
7765 WINED3DRS_FOGVERTEXMODE ,
7766 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7767 WINED3DRS_LIGHTING ,
7768 WINED3DRS_LOCALVIEWER ,
7769 WINED3DRS_MULTISAMPLEANTIALIAS ,
7770 WINED3DRS_MULTISAMPLEMASK ,
7771 WINED3DRS_NORMALIZENORMALS ,
7772 WINED3DRS_PATCHEDGESTYLE ,
7773 WINED3DRS_POINTSCALE_A ,
7774 WINED3DRS_POINTSCALE_B ,
7775 WINED3DRS_POINTSCALE_C ,
7776 WINED3DRS_POINTSCALEENABLE ,
7777 WINED3DRS_POINTSIZE ,
7778 WINED3DRS_POINTSIZE_MAX ,
7779 WINED3DRS_POINTSIZE_MIN ,
7780 WINED3DRS_POINTSPRITEENABLE ,
7781 WINED3DRS_RANGEFOGENABLE ,
7782 WINED3DRS_SPECULARMATERIALSOURCE ,
7783 WINED3DRS_TWEENFACTOR ,
7784 WINED3DRS_VERTEXBLEND ,
7785 WINED3DRS_CULLMODE ,
7789 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7790 WINED3DTSS_TEXCOORDINDEX ,
7791 WINED3DTSS_TEXTURETRANSFORMFLAGS
7794 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7795 WINED3DSAMP_DMAPOFFSET
7798 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7799 DWORD rep = This->shader_backend->StateTable[state].representative;
7803 WineD3DContext *context;
7806 for(i = 0; i < This->numContexts; i++) {
7807 context = This->contexts[i];
7808 if(isStateDirty(context, rep)) continue;
7810 context->dirtyArray[context->numDirtyEntries++] = rep;
7813 context->isStateDirty[idx] |= (1 << shift);
7817 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7818 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7819 /* The drawable size of a pbuffer render target is the current pbuffer size
7821 *width = dev->pbufferWidth;
7822 *height = dev->pbufferHeight;
7825 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7826 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7828 *width = This->pow2Width;
7829 *height = This->pow2Height;
7832 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7833 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7834 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7835 * current context's drawable, which is the size of the back buffer of the swapchain
7836 * the active context belongs to. The back buffer of the swapchain is stored as the
7837 * surface the context belongs to.
7839 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7840 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;