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-2008 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);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
776 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
777 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
778 return WINED3DERR_INVALIDCALL;
781 /* TODO: It should only be possible to create textures for formats
782 that are reported as supported */
783 if (WINED3DFMT_UNKNOWN >= Format) {
784 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
785 return WINED3DERR_INVALIDCALL;
788 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
789 D3DINITIALIZEBASETEXTURE(object->baseTexture);
790 object->width = Width;
791 object->height = Height;
793 /** Non-power2 support **/
794 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
798 /* Find the nearest pow2 match */
799 pow2Width = pow2Height = 1;
800 while (pow2Width < Width) pow2Width <<= 1;
801 while (pow2Height < Height) pow2Height <<= 1;
803 if(pow2Width != Width || pow2Height != Height) {
805 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
806 HeapFree(GetProcessHeap(), 0, object);
808 return WINED3DERR_INVALIDCALL;
815 /** FIXME: add support for real non-power-two if it's provided by the video card **/
816 /* Precalculated scaling for 'faked' non power of two texture coords.
817 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
818 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
819 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
821 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
822 (Width != pow2Width || Height != pow2Height) &&
823 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
825 object->baseTexture.pow2Matrix[0] = (float)Width;
826 object->baseTexture.pow2Matrix[5] = (float)Height;
827 object->baseTexture.pow2Matrix[10] = 1.0;
828 object->baseTexture.pow2Matrix[15] = 1.0;
829 object->target = GL_TEXTURE_RECTANGLE_ARB;
831 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
832 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
833 object->baseTexture.pow2Matrix[10] = 1.0;
834 object->baseTexture.pow2Matrix[15] = 1.0;
835 object->target = GL_TEXTURE_2D;
837 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
839 /* Calculate levels for mip mapping */
840 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
841 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
842 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
843 return WINED3DERR_INVALIDCALL;
846 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
847 return WINED3DERR_INVALIDCALL;
849 object->baseTexture.levels = 1;
850 } else if (Levels == 0) {
851 TRACE("calculating levels %d\n", object->baseTexture.levels);
852 object->baseTexture.levels++;
855 while (tmpW > 1 || tmpH > 1) {
856 tmpW = max(1, tmpW >> 1);
857 tmpH = max(1, tmpH >> 1);
858 object->baseTexture.levels++;
860 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
863 /* Generate all the surfaces */
866 for (i = 0; i < object->baseTexture.levels; i++)
868 /* use the callback to create the texture surface */
869 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
870 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
871 FIXME("Failed to create surface %p\n", object);
873 object->surfaces[i] = NULL;
874 IWineD3DTexture_Release((IWineD3DTexture *)object);
880 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
881 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
882 /* calculate the next mipmap level */
883 tmpW = max(1, tmpW >> 1);
884 tmpH = max(1, tmpH >> 1);
886 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
888 TRACE("(%p) : Created texture %p\n", This, object);
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
893 UINT Width, UINT Height, UINT Depth,
894 UINT Levels, DWORD Usage,
895 WINED3DFORMAT Format, WINED3DPOOL Pool,
896 IWineD3DVolumeTexture **ppVolumeTexture,
897 HANDLE *pSharedHandle, IUnknown *parent,
898 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 IWineD3DVolumeTextureImpl *object;
906 const GlPixelFormatDesc *glDesc;
908 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
910 /* TODO: It should only be possible to create textures for formats
911 that are reported as supported */
912 if (WINED3DFMT_UNKNOWN >= Format) {
913 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
914 return WINED3DERR_INVALIDCALL;
916 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
917 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
918 return WINED3DERR_INVALIDCALL;
921 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
922 D3DINITIALIZEBASETEXTURE(object->baseTexture);
924 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
925 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
927 object->width = Width;
928 object->height = Height;
929 object->depth = Depth;
931 /* Is NP2 support for volumes needed? */
932 object->baseTexture.pow2Matrix[ 0] = 1.0;
933 object->baseTexture.pow2Matrix[ 5] = 1.0;
934 object->baseTexture.pow2Matrix[10] = 1.0;
935 object->baseTexture.pow2Matrix[15] = 1.0;
937 /* Calculate levels for mip mapping */
938 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
939 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
940 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
941 return WINED3DERR_INVALIDCALL;
944 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
948 } else if (Levels == 0) {
949 object->baseTexture.levels++;
953 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
954 tmpW = max(1, tmpW >> 1);
955 tmpH = max(1, tmpH >> 1);
956 tmpD = max(1, tmpD >> 1);
957 object->baseTexture.levels++;
959 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
962 /* Generate all the surfaces */
967 for (i = 0; i < object->baseTexture.levels; i++)
970 /* Create the volume */
971 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
972 &object->volumes[i], pSharedHandle);
975 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
976 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
977 *ppVolumeTexture = NULL;
981 /* Set its container to this object */
982 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
984 /* calculate the next mipmap level */
985 tmpW = max(1, tmpW >> 1);
986 tmpH = max(1, tmpH >> 1);
987 tmpD = max(1, tmpD >> 1);
989 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
991 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
992 TRACE("(%p) : Created volume texture %p\n", This, object);
996 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
997 UINT Width, UINT Height, UINT Depth,
999 WINED3DFORMAT Format, WINED3DPOOL Pool,
1000 IWineD3DVolume** ppVolume,
1001 HANDLE* pSharedHandle, IUnknown *parent) {
1003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1004 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1005 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1007 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1008 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1009 return WINED3DERR_INVALIDCALL;
1012 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1014 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1015 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1017 object->currentDesc.Width = Width;
1018 object->currentDesc.Height = Height;
1019 object->currentDesc.Depth = Depth;
1020 object->bytesPerPixel = formatDesc->bpp;
1022 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1023 object->lockable = TRUE;
1024 object->locked = FALSE;
1025 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1026 object->dirty = TRUE;
1028 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1031 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1032 UINT Levels, DWORD Usage,
1033 WINED3DFORMAT Format, WINED3DPOOL Pool,
1034 IWineD3DCubeTexture **ppCubeTexture,
1035 HANDLE *pSharedHandle, IUnknown *parent,
1036 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1039 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1043 unsigned int pow2EdgeLength = EdgeLength;
1044 const GlPixelFormatDesc *glDesc;
1045 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1047 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
1048 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
1049 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
1050 return WINED3DERR_INVALIDCALL;
1053 /* TODO: It should only be possible to create textures for formats
1054 that are reported as supported */
1055 if (WINED3DFMT_UNKNOWN >= Format) {
1056 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1057 return WINED3DERR_INVALIDCALL;
1060 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1061 WARN("(%p) : Tried to create not supported cube texture\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1066 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1068 TRACE("(%p) Create Cube Texture\n", This);
1070 /** Non-power2 support **/
1072 /* Find the nearest pow2 match */
1074 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1076 object->edgeLength = EdgeLength;
1077 /* TODO: support for native non-power 2 */
1078 /* Precalculated scaling for 'faked' non power of two texture coords */
1079 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1080 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1081 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1082 object->baseTexture.pow2Matrix[15] = 1.0;
1084 /* Calculate levels for mip mapping */
1085 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1086 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1087 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1088 HeapFree(GetProcessHeap(), 0, object);
1089 *ppCubeTexture = NULL;
1091 return WINED3DERR_INVALIDCALL;
1094 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1095 HeapFree(GetProcessHeap(), 0, object);
1096 *ppCubeTexture = NULL;
1098 return WINED3DERR_INVALIDCALL;
1101 } else if (Levels == 0) {
1102 object->baseTexture.levels++;
1105 tmpW = max(1, tmpW >> 1);
1106 object->baseTexture.levels++;
1108 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1111 /* Generate all the surfaces */
1113 for (i = 0; i < object->baseTexture.levels; i++) {
1115 /* Create the 6 faces */
1116 for (j = 0; j < 6; j++) {
1118 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1119 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1121 if(hr!= WINED3D_OK) {
1125 for (l = 0; l < j; l++) {
1126 IWineD3DSurface_Release(object->surfaces[l][i]);
1128 for (k = 0; k < i; k++) {
1129 for (l = 0; l < 6; l++) {
1130 IWineD3DSurface_Release(object->surfaces[l][k]);
1134 FIXME("(%p) Failed to create surface\n",object);
1135 HeapFree(GetProcessHeap(),0,object);
1136 *ppCubeTexture = NULL;
1139 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1140 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1142 tmpW = max(1, tmpW >> 1);
1144 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1146 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1147 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1151 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1153 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1154 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1155 const IWineD3DQueryVtbl *vtable;
1157 /* Just a check to see if we support this type of query */
1159 case WINED3DQUERYTYPE_OCCLUSION:
1160 TRACE("(%p) occlusion query\n", This);
1161 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1164 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1166 vtable = &IWineD3DOcclusionQuery_Vtbl;
1169 case WINED3DQUERYTYPE_EVENT:
1170 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1171 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1172 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1174 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1176 vtable = &IWineD3DEventQuery_Vtbl;
1180 case WINED3DQUERYTYPE_VCACHE:
1181 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1182 case WINED3DQUERYTYPE_VERTEXSTATS:
1183 case WINED3DQUERYTYPE_TIMESTAMP:
1184 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1185 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1186 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1187 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1188 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1189 case WINED3DQUERYTYPE_PIXELTIMINGS:
1190 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1191 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1193 /* Use the base Query vtable until we have a special one for each query */
1194 vtable = &IWineD3DQuery_Vtbl;
1195 FIXME("(%p) Unhandled query type %d\n", This, Type);
1197 if(NULL == ppQuery || hr != WINED3D_OK) {
1201 D3DCREATEOBJECTINSTANCE(object, Query)
1202 object->lpVtbl = vtable;
1203 object->type = Type;
1204 object->state = QUERY_CREATED;
1205 /* allocated the 'extended' data based on the type of query requested */
1207 case WINED3DQUERYTYPE_OCCLUSION:
1208 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1209 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1211 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1212 TRACE("(%p) Allocating data for an occlusion query\n", This);
1213 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1216 case WINED3DQUERYTYPE_EVENT:
1217 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1218 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1220 if(GL_SUPPORT(APPLE_FENCE)) {
1221 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1222 checkGLcall("glGenFencesAPPLE");
1223 } else if(GL_SUPPORT(NV_FENCE)) {
1224 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1225 checkGLcall("glGenFencesNV");
1229 case WINED3DQUERYTYPE_VCACHE:
1230 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1231 case WINED3DQUERYTYPE_VERTEXSTATS:
1232 case WINED3DQUERYTYPE_TIMESTAMP:
1233 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1234 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1235 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1236 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1237 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1238 case WINED3DQUERYTYPE_PIXELTIMINGS:
1239 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1240 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1242 object->extendedData = 0;
1243 FIXME("(%p) Unhandled query type %d\n",This , Type);
1245 TRACE("(%p) : Created Query %p\n", This, object);
1249 /*****************************************************************************
1250 * IWineD3DDeviceImpl_SetupFullscreenWindow
1252 * Helper function that modifies a HWND's Style and ExStyle for proper
1256 * iface: Pointer to the IWineD3DDevice interface
1257 * window: Window to setup
1259 *****************************************************************************/
1260 static LONG fullscreen_style(LONG orig_style) {
1261 LONG style = orig_style;
1262 style &= ~WS_CAPTION;
1263 style &= ~WS_THICKFRAME;
1265 /* Make sure the window is managed, otherwise we won't get keyboard input */
1266 style |= WS_POPUP | WS_SYSMENU;
1271 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1272 LONG exStyle = orig_exStyle;
1274 /* Filter out window decorations */
1275 exStyle &= ~WS_EX_WINDOWEDGE;
1276 exStyle &= ~WS_EX_CLIENTEDGE;
1281 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1284 LONG style, exStyle;
1285 /* Don't do anything if an original style is stored.
1286 * That shouldn't happen
1288 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1289 if (This->style || This->exStyle) {
1290 ERR("(%p): Want to change the window parameters of HWND %p, but "
1291 "another style is stored for restoration afterwards\n", This, window);
1294 /* Get the parameters and save them */
1295 style = GetWindowLongW(window, GWL_STYLE);
1296 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1297 This->style = style;
1298 This->exStyle = exStyle;
1300 style = fullscreen_style(style);
1301 exStyle = fullscreen_exStyle(exStyle);
1303 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1304 This->style, This->exStyle, style, exStyle);
1306 SetWindowLongW(window, GWL_STYLE, style);
1307 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1309 /* Inform the window about the update. */
1310 SetWindowPos(window, HWND_TOP, 0, 0,
1311 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1312 ShowWindow(window, SW_NORMAL);
1315 /*****************************************************************************
1316 * IWineD3DDeviceImpl_RestoreWindow
1318 * Helper function that restores a windows' properties when taking it out
1319 * of fullscreen mode
1322 * iface: Pointer to the IWineD3DDevice interface
1323 * window: Window to setup
1325 *****************************************************************************/
1326 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1328 LONG style, exStyle;
1330 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1331 * switch, do nothing
1333 if (!This->style && !This->exStyle) return;
1335 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1336 This, window, This->style, This->exStyle);
1338 style = GetWindowLongW(window, GWL_STYLE);
1339 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1341 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1342 * Some applications change it before calling Reset() when switching between windowed and
1343 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1345 if(style == fullscreen_style(This->style) &&
1346 exStyle == fullscreen_style(This->exStyle)) {
1347 SetWindowLongW(window, GWL_STYLE, This->style);
1348 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1351 /* Delete the old values */
1355 /* Inform the window about the update */
1356 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1357 0, 0, 0, 0, /* Pos, Size, ignored */
1358 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1361 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1362 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1364 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1365 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1369 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1370 HRESULT hr = WINED3D_OK;
1371 IUnknown *bufferParent;
1372 BOOL displaymode_set = FALSE;
1373 WINED3DDISPLAYMODE Mode;
1374 const StaticPixelFormatDesc *formatDesc;
1376 TRACE("(%p) : Created Additional Swap Chain\n", This);
1378 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1379 * does a device hold a reference to a swap chain giving them a lifetime of the device
1380 * or does the swap chain notify the device of its destruction.
1381 *******************************/
1383 /* Check the params */
1384 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1385 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1386 return WINED3DERR_INVALIDCALL;
1387 } else if (pPresentationParameters->BackBufferCount > 1) {
1388 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");
1391 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1393 /*********************
1394 * Lookup the window Handle and the relating X window handle
1395 ********************/
1397 /* Setup hwnd we are using, plus which display this equates to */
1398 object->win_handle = pPresentationParameters->hDeviceWindow;
1399 if (!object->win_handle) {
1400 object->win_handle = This->createParms.hFocusWindow;
1402 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1404 hDc = GetDC(object->win_handle);
1405 TRACE("Using hDc %p\n", hDc);
1408 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1409 return WINED3DERR_NOTAVAILABLE;
1412 /* Get info on the current display setup */
1413 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1414 object->orig_width = Mode.Width;
1415 object->orig_height = Mode.Height;
1416 object->orig_fmt = Mode.Format;
1417 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1419 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1420 * then the corresponding dimension of the client area of the hDeviceWindow
1421 * (or the focus window, if hDeviceWindow is NULL) is taken.
1422 **********************/
1424 if (pPresentationParameters->Windowed &&
1425 ((pPresentationParameters->BackBufferWidth == 0) ||
1426 (pPresentationParameters->BackBufferHeight == 0) ||
1427 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1430 GetClientRect(object->win_handle, &Rect);
1432 if (pPresentationParameters->BackBufferWidth == 0) {
1433 pPresentationParameters->BackBufferWidth = Rect.right;
1434 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1436 if (pPresentationParameters->BackBufferHeight == 0) {
1437 pPresentationParameters->BackBufferHeight = Rect.bottom;
1438 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1440 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1441 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1442 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1446 /* Put the correct figures in the presentation parameters */
1447 TRACE("Copying across presentation parameters\n");
1448 object->presentParms = *pPresentationParameters;
1450 TRACE("calling rendertarget CB\n");
1451 hr = D3DCB_CreateRenderTarget(This->parent,
1453 object->presentParms.BackBufferWidth,
1454 object->presentParms.BackBufferHeight,
1455 object->presentParms.BackBufferFormat,
1456 object->presentParms.MultiSampleType,
1457 object->presentParms.MultiSampleQuality,
1458 TRUE /* Lockable */,
1459 &object->frontBuffer,
1460 NULL /* pShared (always null)*/);
1461 if (object->frontBuffer != NULL) {
1462 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1463 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1465 ERR("Failed to create the front buffer\n");
1469 /*********************
1470 * Windowed / Fullscreen
1471 *******************/
1474 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1475 * so we should really check to see if there is a fullscreen swapchain already
1476 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1477 **************************************/
1479 if (!pPresentationParameters->Windowed) {
1480 WINED3DDISPLAYMODE mode;
1483 /* Change the display settings */
1484 mode.Width = pPresentationParameters->BackBufferWidth;
1485 mode.Height = pPresentationParameters->BackBufferHeight;
1486 mode.Format = pPresentationParameters->BackBufferFormat;
1487 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1489 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1490 displaymode_set = TRUE;
1491 IWineD3DDevice_SetFullscreen(iface, TRUE);
1495 * Create an opengl context for the display visual
1496 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1497 * use different properties after that point in time. FIXME: How to handle when requested format
1498 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1499 * it chooses is identical to the one already being used!
1500 **********************************/
1501 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1503 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1504 if(!object->context)
1505 return E_OUTOFMEMORY;
1506 object->num_contexts = 1;
1508 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1509 if (!object->context[0]) {
1510 ERR("Failed to create a new context\n");
1511 hr = WINED3DERR_NOTAVAILABLE;
1514 TRACE("Context created (HWND=%p, glContext=%p)\n",
1515 object->win_handle, object->context[0]->glCtx);
1518 /*********************
1519 * Create the back, front and stencil buffers
1520 *******************/
1521 if(object->presentParms.BackBufferCount > 0) {
1524 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1525 if(!object->backBuffer) {
1526 ERR("Out of memory\n");
1531 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1532 TRACE("calling rendertarget CB\n");
1533 hr = D3DCB_CreateRenderTarget(This->parent,
1535 object->presentParms.BackBufferWidth,
1536 object->presentParms.BackBufferHeight,
1537 object->presentParms.BackBufferFormat,
1538 object->presentParms.MultiSampleType,
1539 object->presentParms.MultiSampleQuality,
1540 TRUE /* Lockable */,
1541 &object->backBuffer[i],
1542 NULL /* pShared (always null)*/);
1543 if(hr == WINED3D_OK && object->backBuffer[i]) {
1544 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1546 ERR("Cannot create new back buffer\n");
1550 glDrawBuffer(GL_BACK);
1551 checkGLcall("glDrawBuffer(GL_BACK)");
1555 object->backBuffer = NULL;
1557 /* Single buffering - draw to front buffer */
1559 glDrawBuffer(GL_FRONT);
1560 checkGLcall("glDrawBuffer(GL_FRONT)");
1564 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1565 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1566 TRACE("Creating depth stencil buffer\n");
1567 if (This->auto_depth_stencil_buffer == NULL ) {
1568 hr = D3DCB_CreateDepthStencil(This->parent,
1570 object->presentParms.BackBufferWidth,
1571 object->presentParms.BackBufferHeight,
1572 object->presentParms.AutoDepthStencilFormat,
1573 object->presentParms.MultiSampleType,
1574 object->presentParms.MultiSampleQuality,
1575 FALSE /* FIXME: Discard */,
1576 &This->auto_depth_stencil_buffer,
1577 NULL /* pShared (always null)*/ );
1578 if (This->auto_depth_stencil_buffer != NULL)
1579 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1582 /** TODO: A check on width, height and multisample types
1583 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1584 ****************************/
1585 object->wantsDepthStencilBuffer = TRUE;
1587 object->wantsDepthStencilBuffer = FALSE;
1590 TRACE("Created swapchain %p\n", object);
1591 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1595 if (displaymode_set) {
1599 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1602 /* Change the display settings */
1603 memset(&devmode, 0, sizeof(devmode));
1604 devmode.dmSize = sizeof(devmode);
1605 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1606 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1607 devmode.dmPelsWidth = object->orig_width;
1608 devmode.dmPelsHeight = object->orig_height;
1609 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1612 if (object->backBuffer) {
1614 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1615 if(object->backBuffer[i]) {
1616 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1617 IUnknown_Release(bufferParent); /* once for the get parent */
1618 if (IUnknown_Release(bufferParent) > 0) {
1619 FIXME("(%p) Something's still holding the back buffer\n",This);
1623 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1624 object->backBuffer = NULL;
1626 if(object->context[0])
1627 DestroyContext(This, object->context[0]);
1628 if(object->frontBuffer) {
1629 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1630 IUnknown_Release(bufferParent); /* once for the get parent */
1631 if (IUnknown_Release(bufferParent) > 0) {
1632 FIXME("(%p) Something's still holding the front buffer\n",This);
1635 HeapFree(GetProcessHeap(), 0, object);
1639 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1640 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1642 TRACE("(%p)\n", This);
1644 return This->NumberOfSwapChains;
1647 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1649 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1651 if(iSwapChain < This->NumberOfSwapChains) {
1652 *pSwapChain = This->swapchains[iSwapChain];
1653 IWineD3DSwapChain_AddRef(*pSwapChain);
1654 TRACE("(%p) returning %p\n", This, *pSwapChain);
1657 TRACE("Swapchain out of range\n");
1659 return WINED3DERR_INVALIDCALL;
1664 * Vertex Declaration
1666 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1667 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1669 IWineD3DVertexDeclarationImpl *object = NULL;
1670 HRESULT hr = WINED3D_OK;
1672 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1673 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1675 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1677 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1679 *ppVertexDeclaration = NULL;
1680 HeapFree(GetProcessHeap(), 0, object);
1686 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1687 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1689 unsigned int idx, idx2;
1690 unsigned int offset;
1691 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1692 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1693 BOOL has_blend_idx = has_blend &&
1694 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1695 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1696 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1697 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1698 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1699 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1700 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1702 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1703 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1705 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1706 WINED3DVERTEXELEMENT *elements = NULL;
1709 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1710 if (has_blend_idx) num_blends--;
1712 /* Compute declaration size */
1713 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1714 has_psize + has_diffuse + has_specular + num_textures + 1;
1716 /* convert the declaration */
1717 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1721 elements[size-1] = end_element;
1724 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1725 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1726 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1729 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1730 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1732 elements[idx].UsageIndex = 0;
1735 if (has_blend && (num_blends > 0)) {
1736 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1737 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1739 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1740 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1741 elements[idx].UsageIndex = 0;
1744 if (has_blend_idx) {
1745 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1746 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1747 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1748 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1749 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1751 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1752 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1753 elements[idx].UsageIndex = 0;
1757 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1758 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1759 elements[idx].UsageIndex = 0;
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1765 elements[idx].UsageIndex = 0;
1769 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1770 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1771 elements[idx].UsageIndex = 0;
1775 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1776 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1777 elements[idx].UsageIndex = 1;
1780 for (idx2 = 0; idx2 < num_textures; idx2++) {
1781 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1782 switch (numcoords) {
1783 case WINED3DFVF_TEXTUREFORMAT1:
1784 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1786 case WINED3DFVF_TEXTUREFORMAT2:
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1789 case WINED3DFVF_TEXTUREFORMAT3:
1790 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1792 case WINED3DFVF_TEXTUREFORMAT4:
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1796 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1797 elements[idx].UsageIndex = idx2;
1801 /* Now compute offsets, and initialize the rest of the fields */
1802 for (idx = 0, offset = 0; idx < size-1; idx++) {
1803 elements[idx].Stream = 0;
1804 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1805 elements[idx].Offset = offset;
1806 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1809 *ppVertexElements = elements;
1813 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1814 WINED3DVERTEXELEMENT* elements = NULL;
1815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1819 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1820 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1822 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1823 HeapFree(GetProcessHeap(), 0, elements);
1824 if (hr != S_OK) return hr;
1829 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1830 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1831 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1832 HRESULT hr = WINED3D_OK;
1833 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1834 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1836 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1838 if (vertex_declaration) {
1839 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1842 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1844 if (WINED3D_OK != hr) {
1845 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1846 IWineD3DVertexShader_Release(*ppVertexShader);
1847 return WINED3DERR_INVALIDCALL;
1849 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1854 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1856 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1857 HRESULT hr = WINED3D_OK;
1859 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1860 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1861 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1862 if (WINED3D_OK == hr) {
1863 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1864 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1866 WARN("(%p) : Failed to create pixel shader\n", This);
1872 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1874 IWineD3DPaletteImpl *object;
1876 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1878 /* Create the new object */
1879 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1881 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1882 return E_OUTOFMEMORY;
1885 object->lpVtbl = &IWineD3DPalette_Vtbl;
1887 object->Flags = Flags;
1888 object->parent = Parent;
1889 object->wineD3DDevice = This;
1890 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1892 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1895 HeapFree( GetProcessHeap(), 0, object);
1896 return E_OUTOFMEMORY;
1899 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1901 IWineD3DPalette_Release((IWineD3DPalette *) object);
1905 *Palette = (IWineD3DPalette *) object;
1910 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1914 HDC dcb = NULL, dcs = NULL;
1915 WINEDDCOLORKEY colorkey;
1917 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1920 GetObjectA(hbm, sizeof(BITMAP), &bm);
1921 dcb = CreateCompatibleDC(NULL);
1923 SelectObject(dcb, hbm);
1927 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1928 * couldn't be loaded
1930 memset(&bm, 0, sizeof(bm));
1935 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1936 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1937 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1939 ERR("Wine logo requested, but failed to create surface\n");
1944 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1945 if(FAILED(hr)) goto out;
1946 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1947 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1949 colorkey.dwColorSpaceLowValue = 0;
1950 colorkey.dwColorSpaceHighValue = 0;
1951 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1953 /* Fill the surface with a white color to show that wined3d is there */
1954 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1967 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1969 /* Under DirectX you can have texture stage operations even if no texture is
1970 bound, whereas opengl will only do texture operations when a valid texture is
1971 bound. We emulate this by creating dummy textures and binding them to each
1972 texture stage, but disable all stages by default. Hence if a stage is enabled
1973 then the default texture will kick in until replaced by a SetTexture call */
1976 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1977 /* The dummy texture does not have client storage backing */
1978 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1979 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1981 for (i = 0; i < GL_LIMITS(textures); i++) {
1982 GLubyte white = 255;
1984 /* Make appropriate texture active */
1985 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
1986 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
1987 checkGLcall("glActiveTextureARB");
1989 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
1992 /* Generate an opengl texture name */
1993 glGenTextures(1, &This->dummyTextureName[i]);
1994 checkGLcall("glGenTextures");
1995 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
1997 /* Generate a dummy 2d texture (not using 1d because they cause many
1998 * DRI drivers fall back to sw) */
1999 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2000 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2001 checkGLcall("glBindTexture");
2003 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2004 checkGLcall("glTexImage2D");
2006 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2007 /* Reenable because if supported it is enabled by default */
2008 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2009 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2015 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2017 IWineD3DSwapChainImpl *swapchain = NULL;
2022 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2023 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2024 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2026 /* TODO: Test if OpenGL is compiled in and loaded */
2028 TRACE("(%p) : Creating stateblock\n", This);
2029 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2030 hr = IWineD3DDevice_CreateStateBlock(iface,
2032 (IWineD3DStateBlock **)&This->stateBlock,
2034 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2035 WARN("Failed to create stateblock\n");
2038 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2039 This->updateStateBlock = This->stateBlock;
2040 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2042 hr = allocate_shader_constants(This->updateStateBlock);
2043 if (WINED3D_OK != hr) {
2047 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2048 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2049 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2051 This->NumberOfPalettes = 1;
2052 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2053 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2054 ERR("Out of memory!\n");
2057 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2058 if(!This->palettes[0]) {
2059 ERR("Out of memory!\n");
2062 for (i = 0; i < 256; ++i) {
2063 This->palettes[0][i].peRed = 0xFF;
2064 This->palettes[0][i].peGreen = 0xFF;
2065 This->palettes[0][i].peBlue = 0xFF;
2066 This->palettes[0][i].peFlags = 0xFF;
2068 This->currentPalette = 0;
2070 /* Initialize the texture unit mapping to a 1:1 mapping */
2071 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2072 if (state < GL_LIMITS(fragment_samplers)) {
2073 This->texUnitMap[state] = state;
2074 This->rev_tex_unit_map[state] = state;
2076 This->texUnitMap[state] = -1;
2077 This->rev_tex_unit_map[state] = -1;
2081 /* Setup the implicit swapchain */
2082 TRACE("Creating implicit swapchain\n");
2083 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2084 if (FAILED(hr) || !swapchain) {
2085 WARN("Failed to create implicit swapchain\n");
2089 This->NumberOfSwapChains = 1;
2090 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2091 if(!This->swapchains) {
2092 ERR("Out of memory!\n");
2095 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2097 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2098 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2099 This->render_targets[0] = swapchain->backBuffer[0];
2100 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2103 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2104 This->render_targets[0] = swapchain->frontBuffer;
2105 This->lastActiveRenderTarget = swapchain->frontBuffer;
2107 IWineD3DSurface_AddRef(This->render_targets[0]);
2108 This->activeContext = swapchain->context[0];
2109 This->lastThread = GetCurrentThreadId();
2111 /* Depth Stencil support */
2112 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2113 if (NULL != This->stencilBufferTarget) {
2114 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2117 hr = This->shader_backend->shader_alloc_private(iface);
2119 TRACE("Shader private data couldn't be allocated\n");
2123 /* Set up some starting GL setup */
2126 /* Setup all the devices defaults */
2127 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2128 create_dummy_textures(This);
2130 IWineD3DImpl_CheckGraphicsMemory();
2133 { /* Set a default viewport */
2137 vp.Width = pPresentationParameters->BackBufferWidth;
2138 vp.Height = pPresentationParameters->BackBufferHeight;
2141 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2144 /* Initialize the current view state */
2145 This->view_ident = 1;
2146 This->contexts[0]->last_was_rhw = 0;
2147 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2148 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2150 switch(wined3d_settings.offscreen_rendering_mode) {
2153 This->offscreenBuffer = GL_BACK;
2156 case ORM_BACKBUFFER:
2158 if(GL_LIMITS(aux_buffers) > 0) {
2159 TRACE("Using auxilliary buffer for offscreen rendering\n");
2160 This->offscreenBuffer = GL_AUX0;
2162 TRACE("Using back buffer for offscreen rendering\n");
2163 This->offscreenBuffer = GL_BACK;
2168 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2171 /* Clear the screen */
2172 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2173 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2176 This->d3d_initialized = TRUE;
2178 if(wined3d_settings.logo) {
2179 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2181 This->highest_dirty_ps_const = 0;
2182 This->highest_dirty_vs_const = 0;
2186 This->shader_backend->shader_free_private(iface);
2187 HeapFree(GetProcessHeap(), 0, This->render_targets);
2188 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2189 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2190 HeapFree(GetProcessHeap(), 0, This->swapchains);
2191 This->NumberOfSwapChains = 0;
2192 if(This->palettes) {
2193 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2194 HeapFree(GetProcessHeap(), 0, This->palettes);
2196 This->NumberOfPalettes = 0;
2198 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2200 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2201 if(This->stateBlock) {
2202 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2203 This->stateBlock = NULL;
2208 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2212 TRACE("(%p)\n", This);
2214 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2216 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2217 * it was created. Thus make sure a context is active for the glDelete* calls
2219 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2221 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2223 TRACE("Deleting high order patches\n");
2224 for(i = 0; i < PATCHMAP_SIZE; i++) {
2225 struct list *e1, *e2;
2226 struct WineD3DRectPatch *patch;
2227 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2228 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2229 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2233 /* Delete the palette conversion shader if it is around */
2234 if(This->paletteConversionShader) {
2236 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2238 This->paletteConversionShader = 0;
2241 /* Delete the pbuffer context if there is any */
2242 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2244 /* Delete the mouse cursor texture */
2245 if(This->cursorTexture) {
2247 glDeleteTextures(1, &This->cursorTexture);
2249 This->cursorTexture = 0;
2252 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2253 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2255 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2256 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2259 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2260 * private data, it might contain opengl pointers
2262 This->shader_backend->shader_destroy_depth_blt(iface);
2263 This->shader_backend->shader_free_private(iface);
2265 /* Release the update stateblock */
2266 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2267 if(This->updateStateBlock != This->stateBlock)
2268 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2270 This->updateStateBlock = NULL;
2272 { /* because were not doing proper internal refcounts releasing the primary state block
2273 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2274 to set this->stateBlock = NULL; first */
2275 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2276 This->stateBlock = NULL;
2278 /* Release the stateblock */
2279 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2280 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2284 /* Release the buffers (with sanity checks)*/
2285 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2286 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2287 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2288 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2290 This->stencilBufferTarget = NULL;
2292 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2293 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2294 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2296 TRACE("Setting rendertarget to NULL\n");
2297 This->render_targets[0] = NULL;
2299 if (This->auto_depth_stencil_buffer) {
2300 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2301 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2303 This->auto_depth_stencil_buffer = NULL;
2306 for(i=0; i < This->NumberOfSwapChains; i++) {
2307 TRACE("Releasing the implicit swapchain %d\n", i);
2308 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2309 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2313 HeapFree(GetProcessHeap(), 0, This->swapchains);
2314 This->swapchains = NULL;
2315 This->NumberOfSwapChains = 0;
2317 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2318 HeapFree(GetProcessHeap(), 0, This->palettes);
2319 This->palettes = NULL;
2320 This->NumberOfPalettes = 0;
2322 HeapFree(GetProcessHeap(), 0, This->render_targets);
2323 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2324 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2325 This->render_targets = NULL;
2326 This->fbo_color_attachments = NULL;
2327 This->draw_buffers = NULL;
2329 This->d3d_initialized = FALSE;
2333 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2335 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2337 /* Setup the window for fullscreen mode */
2338 if(fullscreen && !This->ddraw_fullscreen) {
2339 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2340 } else if(!fullscreen && This->ddraw_fullscreen) {
2341 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2344 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2345 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2346 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2349 This->ddraw_fullscreen = fullscreen;
2352 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2353 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2354 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2356 * There is no way to deactivate thread safety once it is enabled.
2358 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2359 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2361 /*For now just store the flag(needed in case of ddraw) */
2362 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2367 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2371 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2374 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2376 /* Resize the screen even without a window:
2377 * The app could have unset it with SetCooperativeLevel, but not called
2378 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2379 * but we don't have any hwnd
2382 memset(&devmode, 0, sizeof(devmode));
2383 devmode.dmSize = sizeof(devmode);
2384 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2385 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2386 devmode.dmPelsWidth = pMode->Width;
2387 devmode.dmPelsHeight = pMode->Height;
2389 devmode.dmDisplayFrequency = pMode->RefreshRate;
2390 if (pMode->RefreshRate != 0) {
2391 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2394 /* Only change the mode if necessary */
2395 if( (This->ddraw_width == pMode->Width) &&
2396 (This->ddraw_height == pMode->Height) &&
2397 (This->ddraw_format == pMode->Format) &&
2398 (pMode->RefreshRate == 0) ) {
2402 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2403 if (ret != DISP_CHANGE_SUCCESSFUL) {
2404 if(devmode.dmDisplayFrequency != 0) {
2405 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2406 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2407 devmode.dmDisplayFrequency = 0;
2408 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2410 if(ret != DISP_CHANGE_SUCCESSFUL) {
2411 return WINED3DERR_NOTAVAILABLE;
2415 /* Store the new values */
2416 This->ddraw_width = pMode->Width;
2417 This->ddraw_height = pMode->Height;
2418 This->ddraw_format = pMode->Format;
2420 /* Only do this with a window of course, and only if we're fullscreened */
2421 if(This->ddraw_window && This->ddraw_fullscreen)
2422 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2424 /* And finally clip mouse to our screen */
2425 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2426 ClipCursor(&clip_rc);
2431 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2432 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2433 *ppD3D= This->wineD3D;
2434 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2435 IWineD3D_AddRef(*ppD3D);
2439 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2440 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2442 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2443 (This->adapter->TextureRam/(1024*1024)),
2444 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2445 /* return simulated texture memory left */
2446 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2454 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2457 /* Update the current state block */
2458 This->updateStateBlock->changed.fvf = TRUE;
2460 if(This->updateStateBlock->fvf == fvf) {
2461 TRACE("Application is setting the old fvf over, nothing to do\n");
2465 This->updateStateBlock->fvf = fvf;
2466 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2467 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2472 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2474 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2475 *pfvf = This->stateBlock->fvf;
2480 * Get / Set Stream Source
2482 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2484 IWineD3DVertexBuffer *oldSrc;
2486 if (StreamNumber >= MAX_STREAMS) {
2487 WARN("Stream out of range %d\n", StreamNumber);
2488 return WINED3DERR_INVALIDCALL;
2489 } else if(OffsetInBytes & 0x3) {
2490 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2491 return WINED3DERR_INVALIDCALL;
2494 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2495 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2497 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2499 if(oldSrc == pStreamData &&
2500 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2501 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2502 TRACE("Application is setting the old values over, nothing to do\n");
2506 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2508 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2509 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2512 /* Handle recording of state blocks */
2513 if (This->isRecordingState) {
2514 TRACE("Recording... not performing anything\n");
2515 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2516 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2520 /* Need to do a getParent and pass the references up */
2521 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2522 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2523 so for now, just count internally */
2524 if (pStreamData != NULL) {
2525 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2526 InterlockedIncrement(&vbImpl->bindCount);
2527 IWineD3DVertexBuffer_AddRef(pStreamData);
2529 if (oldSrc != NULL) {
2530 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2531 IWineD3DVertexBuffer_Release(oldSrc);
2534 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2539 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2542 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2543 This->stateBlock->streamSource[StreamNumber],
2544 This->stateBlock->streamOffset[StreamNumber],
2545 This->stateBlock->streamStride[StreamNumber]);
2547 if (StreamNumber >= MAX_STREAMS) {
2548 WARN("Stream out of range %d\n", StreamNumber);
2549 return WINED3DERR_INVALIDCALL;
2551 *pStream = This->stateBlock->streamSource[StreamNumber];
2552 *pStride = This->stateBlock->streamStride[StreamNumber];
2554 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2557 if (*pStream != NULL) {
2558 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2563 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2566 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2568 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2569 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2571 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2572 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2574 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2575 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2582 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2585 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2586 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2588 TRACE("(%p) : returning %d\n", This, *Divider);
2594 * Get / Set & Multiply Transform
2596 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2599 /* Most of this routine, comments included copied from ddraw tree initially: */
2600 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2602 /* Handle recording of state blocks */
2603 if (This->isRecordingState) {
2604 TRACE("Recording... not performing anything\n");
2605 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2606 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2611 * If the new matrix is the same as the current one,
2612 * we cut off any further processing. this seems to be a reasonable
2613 * optimization because as was noticed, some apps (warcraft3 for example)
2614 * tend towards setting the same matrix repeatedly for some reason.
2616 * From here on we assume that the new matrix is different, wherever it matters.
2618 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2619 TRACE("The app is setting the same matrix over again\n");
2622 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2626 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2627 where ViewMat = Camera space, WorldMat = world space.
2629 In OpenGL, camera and world space is combined into GL_MODELVIEW
2630 matrix. The Projection matrix stay projection matrix.
2633 /* Capture the times we can just ignore the change for now */
2634 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2635 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2636 /* Handled by the state manager */
2639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2643 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2645 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2646 *pMatrix = This->stateBlock->transforms[State];
2650 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2651 WINED3DMATRIX *mat = NULL;
2654 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2655 * below means it will be recorded in a state block change, but it
2656 * works regardless where it is recorded.
2657 * If this is found to be wrong, change to StateBlock.
2659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2660 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2662 if (State < HIGHEST_TRANSFORMSTATE)
2664 mat = &This->updateStateBlock->transforms[State];
2666 FIXME("Unhandled transform state!!\n");
2669 multiply_matrix(&temp, mat, pMatrix);
2671 /* Apply change via set transform - will reapply to eg. lights this way */
2672 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2678 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2679 you can reference any indexes you want as long as that number max are enabled at any
2680 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2681 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2682 but when recording, just build a chain pretty much of commands to be replayed. */
2684 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2686 PLIGHTINFOEL *object = NULL;
2687 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2691 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2693 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2697 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2698 return WINED3DERR_INVALIDCALL;
2701 switch(pLight->Type) {
2702 case WINED3DLIGHT_POINT:
2703 case WINED3DLIGHT_SPOT:
2704 case WINED3DLIGHT_PARALLELPOINT:
2705 case WINED3DLIGHT_GLSPOT:
2706 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2709 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2710 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2711 return WINED3DERR_INVALIDCALL;
2715 case WINED3DLIGHT_DIRECTIONAL:
2716 /* Ignores attenuation */
2720 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2721 return WINED3DERR_INVALIDCALL;
2724 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2725 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2726 if(object->OriginalIndex == Index) break;
2731 TRACE("Adding new light\n");
2732 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2734 ERR("Out of memory error when allocating a light\n");
2735 return E_OUTOFMEMORY;
2737 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2738 object->glIndex = -1;
2739 object->OriginalIndex = Index;
2740 object->changed = TRUE;
2743 /* Initialize the object */
2744 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,
2745 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2746 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2747 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2748 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2749 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2750 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2752 /* Save away the information */
2753 object->OriginalParms = *pLight;
2755 switch (pLight->Type) {
2756 case WINED3DLIGHT_POINT:
2758 object->lightPosn[0] = pLight->Position.x;
2759 object->lightPosn[1] = pLight->Position.y;
2760 object->lightPosn[2] = pLight->Position.z;
2761 object->lightPosn[3] = 1.0f;
2762 object->cutoff = 180.0f;
2766 case WINED3DLIGHT_DIRECTIONAL:
2768 object->lightPosn[0] = -pLight->Direction.x;
2769 object->lightPosn[1] = -pLight->Direction.y;
2770 object->lightPosn[2] = -pLight->Direction.z;
2771 object->lightPosn[3] = 0.0;
2772 object->exponent = 0.0f;
2773 object->cutoff = 180.0f;
2776 case WINED3DLIGHT_SPOT:
2778 object->lightPosn[0] = pLight->Position.x;
2779 object->lightPosn[1] = pLight->Position.y;
2780 object->lightPosn[2] = pLight->Position.z;
2781 object->lightPosn[3] = 1.0;
2784 object->lightDirn[0] = pLight->Direction.x;
2785 object->lightDirn[1] = pLight->Direction.y;
2786 object->lightDirn[2] = pLight->Direction.z;
2787 object->lightDirn[3] = 1.0;
2790 * opengl-ish and d3d-ish spot lights use too different models for the
2791 * light "intensity" as a function of the angle towards the main light direction,
2792 * so we only can approximate very roughly.
2793 * however spot lights are rather rarely used in games (if ever used at all).
2794 * furthermore if still used, probably nobody pays attention to such details.
2796 if (pLight->Falloff == 0) {
2797 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2798 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2799 * will always be 1.0 for both of them, and we don't have to care for the
2800 * rest of the rather complex calculation
2802 object->exponent = 0;
2804 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2805 if (rho < 0.0001) rho = 0.0001f;
2806 object->exponent = -0.3/log(cos(rho/2));
2808 if (object->exponent > 128.0) {
2809 object->exponent = 128.0;
2811 object->cutoff = pLight->Phi*90/M_PI;
2817 FIXME("Unrecognized light type %d\n", pLight->Type);
2820 /* Update the live definitions if the light is currently assigned a glIndex */
2821 if (object->glIndex != -1 && !This->isRecordingState) {
2822 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2827 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2828 PLIGHTINFOEL *lightInfo = NULL;
2829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2830 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2832 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2834 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2835 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2836 if(lightInfo->OriginalIndex == Index) break;
2840 if (lightInfo == NULL) {
2841 TRACE("Light information requested but light not defined\n");
2842 return WINED3DERR_INVALIDCALL;
2845 *pLight = lightInfo->OriginalParms;
2850 * Get / Set Light Enable
2851 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2853 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2854 PLIGHTINFOEL *lightInfo = NULL;
2855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2856 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2858 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2860 /* Tests show true = 128...not clear why */
2861 Enable = Enable? 128: 0;
2863 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2864 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2865 if(lightInfo->OriginalIndex == Index) break;
2868 TRACE("Found light: %p\n", lightInfo);
2870 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2871 if (lightInfo == NULL) {
2873 TRACE("Light enabled requested but light not defined, so defining one!\n");
2874 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2876 /* Search for it again! Should be fairly quick as near head of list */
2877 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2878 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2879 if(lightInfo->OriginalIndex == Index) break;
2882 if (lightInfo == NULL) {
2883 FIXME("Adding default lights has failed dismally\n");
2884 return WINED3DERR_INVALIDCALL;
2888 lightInfo->enabledChanged = TRUE;
2890 if(lightInfo->glIndex != -1) {
2891 if(!This->isRecordingState) {
2892 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2895 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2896 lightInfo->glIndex = -1;
2898 TRACE("Light already disabled, nothing to do\n");
2900 lightInfo->enabled = FALSE;
2902 lightInfo->enabled = TRUE;
2903 if (lightInfo->glIndex != -1) {
2905 TRACE("Nothing to do as light was enabled\n");
2908 /* Find a free gl light */
2909 for(i = 0; i < This->maxConcurrentLights; i++) {
2910 if(This->stateBlock->activeLights[i] == NULL) {
2911 This->stateBlock->activeLights[i] = lightInfo;
2912 lightInfo->glIndex = i;
2916 if(lightInfo->glIndex == -1) {
2917 /* Our tests show that Windows returns D3D_OK in this situation, even with
2918 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2919 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2920 * as well for those lights.
2922 * TODO: Test how this affects rendering
2924 FIXME("Too many concurrently active lights\n");
2928 /* i == lightInfo->glIndex */
2929 if(!This->isRecordingState) {
2930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2938 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2940 PLIGHTINFOEL *lightInfo = NULL;
2941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2944 TRACE("(%p) : for idx(%d)\n", This, Index);
2946 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2947 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2948 if(lightInfo->OriginalIndex == Index) break;
2952 if (lightInfo == NULL) {
2953 TRACE("Light enabled state requested but light not defined\n");
2954 return WINED3DERR_INVALIDCALL;
2956 /* true is 128 according to SetLightEnable */
2957 *pEnable = lightInfo->enabled ? 128 : 0;
2962 * Get / Set Clip Planes
2964 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
2968 /* Validate Index */
2969 if (Index >= GL_LIMITS(clipplanes)) {
2970 TRACE("Application has requested clipplane this device doesn't support\n");
2971 return WINED3DERR_INVALIDCALL;
2974 This->updateStateBlock->changed.clipplane[Index] = TRUE;
2976 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
2977 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
2978 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
2979 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
2980 TRACE("Application is setting old values over, nothing to do\n");
2984 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
2985 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
2986 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
2987 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
2989 /* Handle recording of state blocks */
2990 if (This->isRecordingState) {
2991 TRACE("Recording... not performing anything\n");
2995 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3000 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3002 TRACE("(%p) : for idx %d\n", This, Index);
3004 /* Validate Index */
3005 if (Index >= GL_LIMITS(clipplanes)) {
3006 TRACE("Application has requested clipplane this device doesn't support\n");
3007 return WINED3DERR_INVALIDCALL;
3010 pPlane[0] = This->stateBlock->clipplane[Index][0];
3011 pPlane[1] = This->stateBlock->clipplane[Index][1];
3012 pPlane[2] = This->stateBlock->clipplane[Index][2];
3013 pPlane[3] = This->stateBlock->clipplane[Index][3];
3018 * Get / Set Clip Plane Status
3019 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3021 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3023 FIXME("(%p) : stub\n", This);
3024 if (NULL == pClipStatus) {
3025 return WINED3DERR_INVALIDCALL;
3027 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3028 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3032 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3034 FIXME("(%p) : stub\n", This);
3035 if (NULL == pClipStatus) {
3036 return WINED3DERR_INVALIDCALL;
3038 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3039 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3044 * Get / Set Material
3046 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3047 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3049 This->updateStateBlock->changed.material = TRUE;
3050 This->updateStateBlock->material = *pMaterial;
3052 /* Handle recording of state blocks */
3053 if (This->isRecordingState) {
3054 TRACE("Recording... not performing anything\n");
3058 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3062 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 *pMaterial = This->updateStateBlock->material;
3065 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3066 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3067 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3068 pMaterial->Ambient.b, pMaterial->Ambient.a);
3069 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3070 pMaterial->Specular.b, pMaterial->Specular.a);
3071 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3072 pMaterial->Emissive.b, pMaterial->Emissive.a);
3073 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3081 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 IWineD3DIndexBuffer *oldIdxs;
3085 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3086 oldIdxs = This->updateStateBlock->pIndexData;
3088 This->updateStateBlock->changed.indices = TRUE;
3089 This->updateStateBlock->pIndexData = pIndexData;
3091 /* Handle recording of state blocks */
3092 if (This->isRecordingState) {
3093 TRACE("Recording... not performing anything\n");
3094 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3095 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3099 if(oldIdxs != pIndexData) {
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3101 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3102 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3107 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3108 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 *ppIndexData = This->stateBlock->pIndexData;
3112 /* up ref count on ppindexdata */
3114 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3115 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3117 TRACE("(%p) No index data set\n", This);
3119 TRACE("Returning %p\n", *ppIndexData);
3124 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3125 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3127 TRACE("(%p)->(%d)\n", This, BaseIndex);
3129 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3130 TRACE("Application is setting the old value over, nothing to do\n");
3134 This->updateStateBlock->baseVertexIndex = BaseIndex;
3136 if (This->isRecordingState) {
3137 TRACE("Recording... not performing anything\n");
3140 /* The base vertex index affects the stream sources */
3141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3145 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 TRACE("(%p) : base_index %p\n", This, base_index);
3149 *base_index = This->stateBlock->baseVertexIndex;
3151 TRACE("Returning %u\n", *base_index);
3157 * Get / Set Viewports
3159 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 TRACE("(%p)\n", This);
3163 This->updateStateBlock->changed.viewport = TRUE;
3164 This->updateStateBlock->viewport = *pViewport;
3166 /* Handle recording of state blocks */
3167 if (This->isRecordingState) {
3168 TRACE("Recording... not performing anything\n");
3172 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3173 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3180 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3182 TRACE("(%p)\n", This);
3183 *pViewport = This->stateBlock->viewport;
3188 * Get / Set Render States
3189 * TODO: Verify against dx9 definitions
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3194 DWORD oldValue = This->stateBlock->renderState[State];
3196 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3198 This->updateStateBlock->changed.renderState[State] = TRUE;
3199 This->updateStateBlock->renderState[State] = Value;
3201 /* Handle recording of state blocks */
3202 if (This->isRecordingState) {
3203 TRACE("Recording... not performing anything\n");
3207 /* Compared here and not before the assignment to allow proper stateblock recording */
3208 if(Value == oldValue) {
3209 TRACE("Application is setting the old value over, nothing to do\n");
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3219 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3220 *pValue = This->stateBlock->renderState[State];
3225 * Get / Set Sampler States
3226 * TODO: Verify against dx9 definitions
3229 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3230 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3233 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3234 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3236 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3237 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3240 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3241 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3242 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3245 * SetSampler is designed to allow for more than the standard up to 8 textures
3246 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3247 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3249 * http://developer.nvidia.com/object/General_FAQ.html#t6
3251 * There are two new settings for GForce
3253 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3254 * and the texture one:
3255 * GL_MAX_TEXTURE_COORDS_ARB.
3256 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3259 oldValue = This->stateBlock->samplerState[Sampler][Type];
3260 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3261 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3263 /* Handle recording of state blocks */
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3269 if(oldValue == Value) {
3270 TRACE("Application is setting the old value over, nothing to do\n");
3274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3279 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3280 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3282 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3283 This, Sampler, debug_d3dsamplerstate(Type), Type);
3285 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3286 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3289 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3290 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3291 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3293 *Value = This->stateBlock->samplerState[Sampler][Type];
3294 TRACE("(%p) : Returning %#x\n", This, *Value);
3299 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3302 This->updateStateBlock->changed.scissorRect = TRUE;
3303 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3304 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3307 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3309 if(This->isRecordingState) {
3310 TRACE("Recording... not performing anything\n");
3314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 *pRect = This->updateStateBlock->scissorRect;
3323 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3327 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3329 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3331 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3333 This->updateStateBlock->vertexDecl = pDecl;
3334 This->updateStateBlock->changed.vertexDecl = TRUE;
3336 if (This->isRecordingState) {
3337 TRACE("Recording... not performing anything\n");
3339 } else if(pDecl == oldDecl) {
3340 /* Checked after the assignment to allow proper stateblock recording */
3341 TRACE("Application is setting the old declaration over, nothing to do\n");
3345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3349 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3352 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3354 *ppDecl = This->stateBlock->vertexDecl;
3355 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3359 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3361 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3363 This->updateStateBlock->vertexShader = pShader;
3364 This->updateStateBlock->changed.vertexShader = TRUE;
3366 if (This->isRecordingState) {
3367 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3368 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3369 TRACE("Recording... not performing anything\n");
3371 } else if(oldShader == pShader) {
3372 /* Checked here to allow proper stateblock recording */
3373 TRACE("App is setting the old shader over, nothing to do\n");
3377 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3378 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3379 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3386 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3389 if (NULL == ppShader) {
3390 return WINED3DERR_INVALIDCALL;
3392 *ppShader = This->stateBlock->vertexShader;
3393 if( NULL != *ppShader)
3394 IWineD3DVertexShader_AddRef(*ppShader);
3396 TRACE("(%p) : returning %p\n", This, *ppShader);
3400 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3401 IWineD3DDevice *iface,
3403 CONST BOOL *srcData,
3406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 int i, cnt = min(count, MAX_CONST_B - start);
3409 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3410 iface, srcData, start, count);
3412 if (srcData == NULL || cnt < 0)
3413 return WINED3DERR_INVALIDCALL;
3415 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3416 for (i = 0; i < cnt; i++)
3417 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3419 for (i = start; i < cnt + start; ++i) {
3420 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3428 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3429 IWineD3DDevice *iface,
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 int cnt = min(count, MAX_CONST_B - start);
3437 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3438 iface, dstData, start, count);
3440 if (dstData == NULL || cnt < 0)
3441 return WINED3DERR_INVALIDCALL;
3443 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3447 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3448 IWineD3DDevice *iface,
3453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3454 int i, cnt = min(count, MAX_CONST_I - start);
3456 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3457 iface, srcData, start, count);
3459 if (srcData == NULL || cnt < 0)
3460 return WINED3DERR_INVALIDCALL;
3462 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3463 for (i = 0; i < cnt; i++)
3464 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3465 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3467 for (i = start; i < cnt + start; ++i) {
3468 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3471 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3476 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3477 IWineD3DDevice *iface,
3482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3483 int cnt = min(count, MAX_CONST_I - start);
3485 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3486 iface, dstData, start, count);
3488 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3489 return WINED3DERR_INVALIDCALL;
3491 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3495 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3496 IWineD3DDevice *iface,
3498 CONST float *srcData,
3501 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3505 iface, srcData, start, count);
3507 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3508 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3509 return WINED3DERR_INVALIDCALL;
3511 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3513 for (i = 0; i < count; i++)
3514 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3515 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3518 for (i = start; i < count + start; ++i) {
3519 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3520 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3521 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3522 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3523 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3525 ptr->idx[ptr->count++] = i;
3526 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3530 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3535 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3536 IWineD3DDevice *iface,
3538 CONST float *srcData,
3541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3545 iface, srcData, start, count);
3547 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3548 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3549 return WINED3DERR_INVALIDCALL;
3551 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3553 for (i = 0; i < count; i++)
3554 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3555 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3558 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3559 * context. On a context switch the old context will be fully dirtified
3561 memset(This->activeContext->vshader_const_dirty + start, 1,
3562 sizeof(*This->activeContext->vshader_const_dirty) * count);
3563 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3565 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3570 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3571 IWineD3DDevice *iface,
3576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3577 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3579 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3580 iface, dstData, start, count);
3582 if (dstData == NULL || cnt < 0)
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3589 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3591 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3592 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3596 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3597 int i = This->rev_tex_unit_map[unit];
3598 int j = This->texUnitMap[stage];
3600 This->texUnitMap[stage] = unit;
3601 if (i != -1 && i != stage) {
3602 This->texUnitMap[i] = -1;
3605 This->rev_tex_unit_map[unit] = stage;
3606 if (j != -1 && j != unit) {
3607 This->rev_tex_unit_map[j] = -1;
3611 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3614 for (i = 0; i < MAX_TEXTURES; ++i) {
3615 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3616 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3617 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3618 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3619 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3620 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3621 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3622 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3624 if (color_op == WINED3DTOP_DISABLE) {
3625 /* Not used, and disable higher stages */
3626 while (i < MAX_TEXTURES) {
3627 This->fixed_function_usage_map[i] = FALSE;
3633 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3634 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3635 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3636 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3637 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3638 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3639 This->fixed_function_usage_map[i] = TRUE;
3641 This->fixed_function_usage_map[i] = FALSE;
3644 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3645 This->fixed_function_usage_map[i+1] = TRUE;
3650 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3653 device_update_fixed_function_usage_map(This);
3655 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3656 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3657 if (!This->fixed_function_usage_map[i]) continue;
3659 if (This->texUnitMap[i] != i) {
3660 device_map_stage(This, i, i);
3661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3662 markTextureStagesDirty(This, i);
3668 /* Now work out the mapping */
3670 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3671 if (!This->fixed_function_usage_map[i]) continue;
3673 if (This->texUnitMap[i] != tex) {
3674 device_map_stage(This, i, tex);
3675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3676 markTextureStagesDirty(This, i);
3683 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3684 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3687 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3688 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3689 device_map_stage(This, i, i);
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3691 if (i < MAX_TEXTURES) {
3692 markTextureStagesDirty(This, i);
3698 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3699 int current_mapping = This->rev_tex_unit_map[unit];
3701 if (current_mapping == -1) {
3702 /* Not currently used */
3706 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3707 /* Used by a fragment sampler */
3709 if (!pshader_sampler_tokens) {
3710 /* No pixel shader, check fixed function */
3711 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3714 /* Pixel shader, check the shader's sampler map */
3715 return !pshader_sampler_tokens[current_mapping];
3718 /* Used by a vertex sampler */
3719 return !vshader_sampler_tokens[current_mapping];
3722 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3723 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3724 DWORD *pshader_sampler_tokens = NULL;
3725 int start = GL_LIMITS(combined_samplers) - 1;
3729 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3731 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3732 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3733 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3736 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3737 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3738 if (vshader_sampler_tokens[i]) {
3739 if (This->texUnitMap[vsampler_idx] != -1) {
3740 /* Already mapped somewhere */
3744 while (start >= 0) {
3745 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3746 device_map_stage(This, vsampler_idx, start);
3747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3759 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3760 BOOL vs = use_vs(This);
3761 BOOL ps = use_ps(This);
3764 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3765 * that would be really messy and require shader recompilation
3766 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3767 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3770 device_map_psamplers(This);
3772 device_map_fixed_function_samplers(This);
3776 device_map_vsamplers(This, ps);
3780 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3782 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3783 This->updateStateBlock->pixelShader = pShader;
3784 This->updateStateBlock->changed.pixelShader = TRUE;
3786 /* Handle recording of state blocks */
3787 if (This->isRecordingState) {
3788 TRACE("Recording... not performing anything\n");
3791 if (This->isRecordingState) {
3792 TRACE("Recording... not performing anything\n");
3793 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3794 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3798 if(pShader == oldShader) {
3799 TRACE("App is setting the old pixel shader over, nothing to do\n");
3803 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3804 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3806 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3807 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3812 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3813 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3815 if (NULL == ppShader) {
3816 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3817 return WINED3DERR_INVALIDCALL;
3820 *ppShader = This->stateBlock->pixelShader;
3821 if (NULL != *ppShader) {
3822 IWineD3DPixelShader_AddRef(*ppShader);
3824 TRACE("(%p) : returning %p\n", This, *ppShader);
3828 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3829 IWineD3DDevice *iface,
3831 CONST BOOL *srcData,
3834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3835 int i, cnt = min(count, MAX_CONST_B - start);
3837 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3838 iface, srcData, start, count);
3840 if (srcData == NULL || cnt < 0)
3841 return WINED3DERR_INVALIDCALL;
3843 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3844 for (i = 0; i < cnt; i++)
3845 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3847 for (i = start; i < cnt + start; ++i) {
3848 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3851 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3856 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3857 IWineD3DDevice *iface,
3862 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3863 int cnt = min(count, MAX_CONST_B - start);
3865 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3866 iface, dstData, start, count);
3868 if (dstData == NULL || cnt < 0)
3869 return WINED3DERR_INVALIDCALL;
3871 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3875 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3876 IWineD3DDevice *iface,
3881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3882 int i, cnt = min(count, MAX_CONST_I - start);
3884 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3885 iface, srcData, start, count);
3887 if (srcData == NULL || cnt < 0)
3888 return WINED3DERR_INVALIDCALL;
3890 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3891 for (i = 0; i < cnt; i++)
3892 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3893 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3895 for (i = start; i < cnt + start; ++i) {
3896 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3899 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3904 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3905 IWineD3DDevice *iface,
3910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3911 int cnt = min(count, MAX_CONST_I - start);
3913 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3914 iface, dstData, start, count);
3916 if (dstData == NULL || cnt < 0)
3917 return WINED3DERR_INVALIDCALL;
3919 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3923 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3924 IWineD3DDevice *iface,
3926 CONST float *srcData,
3929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3932 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3933 iface, srcData, start, count);
3935 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3936 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3937 return WINED3DERR_INVALIDCALL;
3939 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3941 for (i = 0; i < count; i++)
3942 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3943 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3946 for (i = start; i < count + start; ++i) {
3947 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3948 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3949 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3950 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3951 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3953 ptr->idx[ptr->count++] = i;
3954 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3963 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
3964 IWineD3DDevice *iface,
3966 CONST float *srcData,
3969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3973 iface, srcData, start, count);
3975 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3976 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3977 return WINED3DERR_INVALIDCALL;
3979 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3981 for (i = 0; i < count; i++)
3982 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3983 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3986 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3987 * context. On a context switch the old context will be fully dirtified
3989 memset(This->activeContext->pshader_const_dirty + start, 1,
3990 sizeof(*This->activeContext->pshader_const_dirty) * count);
3991 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
3993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3998 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3999 IWineD3DDevice *iface,
4004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4005 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4007 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4008 iface, dstData, start, count);
4010 if (dstData == NULL || cnt < 0)
4011 return WINED3DERR_INVALIDCALL;
4013 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4017 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4019 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4020 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4022 DWORD DestFVF = dest->fvf;
4024 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4028 if (lpStrideData->u.s.normal.lpData) {
4029 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4032 if (lpStrideData->u.s.position.lpData == NULL) {
4033 ERR("Source has no position mask\n");
4034 return WINED3DERR_INVALIDCALL;
4037 /* We might access VBOs from this code, so hold the lock */
4040 if (dest->resource.allocatedMemory == NULL) {
4041 /* This may happen if we do direct locking into a vbo. Unlikely,
4042 * but theoretically possible(ddraw processvertices test)
4044 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4045 if(!dest->resource.allocatedMemory) {
4047 ERR("Out of memory\n");
4048 return E_OUTOFMEMORY;
4052 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4053 checkGLcall("glBindBufferARB");
4054 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4056 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4058 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4059 checkGLcall("glUnmapBufferARB");
4063 /* Get a pointer into the destination vbo(create one if none exists) and
4064 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4066 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4067 dest->Flags |= VBFLAG_CREATEVBO;
4068 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4072 unsigned char extrabytes = 0;
4073 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4074 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4075 * this may write 4 extra bytes beyond the area that should be written
4077 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4078 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4079 if(!dest_conv_addr) {
4080 ERR("Out of memory\n");
4081 /* Continue without storing converted vertices */
4083 dest_conv = dest_conv_addr;
4087 * a) WINED3DRS_CLIPPING is enabled
4088 * b) WINED3DVOP_CLIP is passed
4090 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4091 static BOOL warned = FALSE;
4093 * The clipping code is not quite correct. Some things need
4094 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4095 * so disable clipping for now.
4096 * (The graphics in Half-Life are broken, and my processvertices
4097 * test crashes with IDirect3DDevice3)
4103 FIXME("Clipping is broken and disabled for now\n");
4105 } else doClip = FALSE;
4106 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4108 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4111 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4112 WINED3DTS_PROJECTION,
4114 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4115 WINED3DTS_WORLDMATRIX(0),
4118 TRACE("View mat:\n");
4119 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);
4120 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);
4121 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);
4122 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);
4124 TRACE("Proj mat:\n");
4125 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);
4126 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);
4127 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);
4128 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);
4130 TRACE("World mat:\n");
4131 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);
4132 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);
4133 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);
4134 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);
4136 /* Get the viewport */
4137 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4138 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4139 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4141 multiply_matrix(&mat,&view_mat,&world_mat);
4142 multiply_matrix(&mat,&proj_mat,&mat);
4144 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4146 for (i = 0; i < dwCount; i+= 1) {
4147 unsigned int tex_index;
4149 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4150 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4151 /* The position first */
4153 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4155 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4157 /* Multiplication with world, view and projection matrix */
4158 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);
4159 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);
4160 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);
4161 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);
4163 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4165 /* WARNING: The following things are taken from d3d7 and were not yet checked
4166 * against d3d8 or d3d9!
4169 /* Clipping conditions: From msdn
4171 * A vertex is clipped if it does not match the following requirements
4175 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4177 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4178 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4183 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4184 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4187 /* "Normal" viewport transformation (not clipped)
4188 * 1) The values are divided by rhw
4189 * 2) The y axis is negative, so multiply it with -1
4190 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4191 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4192 * 4) Multiply x with Width/2 and add Width/2
4193 * 5) The same for the height
4194 * 6) Add the viewpoint X and Y to the 2D coordinates and
4195 * The minimum Z value to z
4196 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4198 * Well, basically it's simply a linear transformation into viewport
4210 z *= vp.MaxZ - vp.MinZ;
4212 x += vp.Width / 2 + vp.X;
4213 y += vp.Height / 2 + vp.Y;
4218 /* That vertex got clipped
4219 * Contrary to OpenGL it is not dropped completely, it just
4220 * undergoes a different calculation.
4222 TRACE("Vertex got clipped\n");
4229 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4230 * outside of the main vertex buffer memory. That needs some more
4235 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4238 ( (float *) dest_ptr)[0] = x;
4239 ( (float *) dest_ptr)[1] = y;
4240 ( (float *) dest_ptr)[2] = z;
4241 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4243 dest_ptr += 3 * sizeof(float);
4245 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4246 dest_ptr += sizeof(float);
4251 ( (float *) dest_conv)[0] = x * w;
4252 ( (float *) dest_conv)[1] = y * w;
4253 ( (float *) dest_conv)[2] = z * w;
4254 ( (float *) dest_conv)[3] = w;
4256 dest_conv += 3 * sizeof(float);
4258 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4259 dest_conv += sizeof(float);
4263 if (DestFVF & WINED3DFVF_PSIZE) {
4264 dest_ptr += sizeof(DWORD);
4265 if(dest_conv) dest_conv += sizeof(DWORD);
4267 if (DestFVF & WINED3DFVF_NORMAL) {
4269 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4270 /* AFAIK this should go into the lighting information */
4271 FIXME("Didn't expect the destination to have a normal\n");
4272 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4274 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4278 if (DestFVF & WINED3DFVF_DIFFUSE) {
4280 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4282 static BOOL warned = FALSE;
4285 ERR("No diffuse color in source, but destination has one\n");
4289 *( (DWORD *) dest_ptr) = 0xffffffff;
4290 dest_ptr += sizeof(DWORD);
4293 *( (DWORD *) dest_conv) = 0xffffffff;
4294 dest_conv += sizeof(DWORD);
4298 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4300 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4301 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4302 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4303 dest_conv += sizeof(DWORD);
4308 if (DestFVF & WINED3DFVF_SPECULAR) {
4309 /* What's the color value in the feedback buffer? */
4311 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4313 static BOOL warned = FALSE;
4316 ERR("No specular color in source, but destination has one\n");
4320 *( (DWORD *) dest_ptr) = 0xFF000000;
4321 dest_ptr += sizeof(DWORD);
4324 *( (DWORD *) dest_conv) = 0xFF000000;
4325 dest_conv += sizeof(DWORD);
4329 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4331 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4332 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4333 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4334 dest_conv += sizeof(DWORD);
4339 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4341 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4342 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4344 ERR("No source texture, but destination requests one\n");
4345 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4349 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4351 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4358 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4359 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4360 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4361 dwCount * get_flexible_vertex_size(DestFVF),
4363 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4364 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4371 #undef copy_and_next
4373 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4375 WineDirect3DVertexStridedData strided;
4376 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4377 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4380 ERR("Output vertex declaration not implemented yet\n");
4383 /* Need any context to write to the vbo. */
4384 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4386 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4387 * control the streamIsUP flag, thus restore it afterwards.
4389 This->stateBlock->streamIsUP = FALSE;
4390 memset(&strided, 0, sizeof(strided));
4391 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4392 This->stateBlock->streamIsUP = streamWasUP;
4394 if(vbo || SrcStartIndex) {
4396 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4397 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4399 * Also get the start index in, but only loop over all elements if there's something to add at all.
4401 #define FIXSRC(type) \
4402 if(strided.u.s.type.VBO) { \
4403 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4404 strided.u.s.type.VBO = 0; \
4405 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4407 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4411 if(strided.u.s.type.lpData) { \
4412 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4415 FIXSRC(blendWeights);
4416 FIXSRC(blendMatrixIndices);
4421 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4422 FIXSRC(texCoords[i]);
4435 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4439 * Get / Set Texture Stage States
4440 * TODO: Verify against dx9 definitions
4442 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4446 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4448 if (Stage >= MAX_TEXTURES) {
4449 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4453 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4454 This->updateStateBlock->textureState[Stage][Type] = Value;
4456 if (This->isRecordingState) {
4457 TRACE("Recording... not performing anything\n");
4461 /* Checked after the assignments to allow proper stateblock recording */
4462 if(oldValue == Value) {
4463 TRACE("App is setting the old value over, nothing to do\n");
4467 if(Stage > This->stateBlock->lowest_disabled_stage &&
4468 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4469 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4470 * Changes in other states are important on disabled stages too
4475 if(Type == WINED3DTSS_COLOROP) {
4478 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4479 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4480 * they have to be disabled
4482 * The current stage is dirtified below.
4484 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4485 TRACE("Additionally dirtifying stage %d\n", i);
4486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4488 This->stateBlock->lowest_disabled_stage = Stage;
4489 TRACE("New lowest disabled: %d\n", Stage);
4490 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4491 /* Previously disabled stage enabled. Stages above it may need enabling
4492 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4493 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4495 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4498 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4499 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4502 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4505 This->stateBlock->lowest_disabled_stage = i;
4506 TRACE("New lowest disabled: %d\n", i);
4508 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4509 /* TODO: Built a stage -> texture unit mapping for register combiners */
4513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4518 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4520 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4521 *pValue = This->updateStateBlock->textureState[Stage][Type];
4528 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4529 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4530 IWineD3DBaseTexture *oldTexture;
4532 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4534 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4535 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4538 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4539 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4540 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4543 oldTexture = This->updateStateBlock->textures[Stage];
4545 if(pTexture != NULL) {
4546 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4548 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4549 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4550 return WINED3DERR_INVALIDCALL;
4552 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4555 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4556 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4558 This->updateStateBlock->changed.textures[Stage] = TRUE;
4559 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4560 This->updateStateBlock->textures[Stage] = pTexture;
4562 /* Handle recording of state blocks */
4563 if (This->isRecordingState) {
4564 TRACE("Recording... not performing anything\n");
4568 if(oldTexture == pTexture) {
4569 TRACE("App is setting the same texture again, nothing to do\n");
4573 /** NOTE: MSDN says that setTexture increases the reference count,
4574 * and that the application must set the texture back to null (or have a leaky application),
4575 * This means we should pass the refcount up to the parent
4576 *******************************/
4577 if (NULL != This->updateStateBlock->textures[Stage]) {
4578 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4579 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4581 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4582 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4583 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4584 * so the COLOROP and ALPHAOP have to be dirtified.
4586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4587 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4589 if(bindCount == 1) {
4590 new->baseTexture.sampler = Stage;
4592 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4596 if (NULL != oldTexture) {
4597 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4598 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4600 IWineD3DBaseTexture_Release(oldTexture);
4601 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4603 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4606 if(bindCount && old->baseTexture.sampler == Stage) {
4608 /* Have to do a search for the other sampler(s) where the texture is bound to
4609 * Shouldn't happen as long as apps bind a texture only to one stage
4611 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4612 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4613 if(This->updateStateBlock->textures[i] == oldTexture) {
4614 old->baseTexture.sampler = i;
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4626 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4631 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4632 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4635 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4636 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4637 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4640 *ppTexture=This->stateBlock->textures[Stage];
4642 IWineD3DBaseTexture_AddRef(*ppTexture);
4644 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4652 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4653 IWineD3DSurface **ppBackBuffer) {
4654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4655 IWineD3DSwapChain *swapChain;
4658 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4660 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4661 if (hr == WINED3D_OK) {
4662 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4663 IWineD3DSwapChain_Release(swapChain);
4665 *ppBackBuffer = NULL;
4670 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 WARN("(%p) : stub, calling idirect3d for now\n", This);
4673 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4676 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4678 IWineD3DSwapChain *swapChain;
4681 if(iSwapChain > 0) {
4682 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4683 if (hr == WINED3D_OK) {
4684 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4685 IWineD3DSwapChain_Release(swapChain);
4687 FIXME("(%p) Error getting display mode\n", This);
4690 /* Don't read the real display mode,
4691 but return the stored mode instead. X11 can't change the color
4692 depth, and some apps are pretty angry if they SetDisplayMode from
4693 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4695 Also don't relay to the swapchain because with ddraw it's possible
4696 that there isn't a swapchain at all */
4697 pMode->Width = This->ddraw_width;
4698 pMode->Height = This->ddraw_height;
4699 pMode->Format = This->ddraw_format;
4700 pMode->RefreshRate = 0;
4707 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4708 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4709 TRACE("(%p)->(%p)\n", This, hWnd);
4711 if(This->ddraw_fullscreen) {
4712 if(This->ddraw_window && This->ddraw_window != hWnd) {
4713 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4715 if(hWnd && This->ddraw_window != hWnd) {
4716 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4720 This->ddraw_window = hWnd;
4724 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4726 TRACE("(%p)->(%p)\n", This, hWnd);
4728 *hWnd = This->ddraw_window;
4733 * Stateblock related functions
4736 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4738 IWineD3DStateBlockImpl *object;
4739 HRESULT temp_result;
4742 TRACE("(%p)\n", This);
4744 if (This->isRecordingState) {
4745 return WINED3DERR_INVALIDCALL;
4748 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4749 if (NULL == object ) {
4750 FIXME("(%p)Error allocating memory for stateblock\n", This);
4751 return E_OUTOFMEMORY;
4753 TRACE("(%p) created object %p\n", This, object);
4754 object->wineD3DDevice= This;
4755 /** FIXME: object->parent = parent; **/
4756 object->parent = NULL;
4757 object->blockType = WINED3DSBT_RECORDED;
4759 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4761 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4762 list_init(&object->lightMap[i]);
4765 temp_result = allocate_shader_constants(object);
4766 if (WINED3D_OK != temp_result)
4769 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4770 This->updateStateBlock = object;
4771 This->isRecordingState = TRUE;
4773 TRACE("(%p) recording stateblock %p\n",This , object);
4777 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4782 if (!This->isRecordingState) {
4783 FIXME("(%p) not recording! returning error\n", This);
4784 *ppStateBlock = NULL;
4785 return WINED3DERR_INVALIDCALL;
4788 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4789 if(object->changed.renderState[i]) {
4790 object->contained_render_states[object->num_contained_render_states] = i;
4791 object->num_contained_render_states++;
4794 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4795 if(object->changed.transform[i]) {
4796 object->contained_transform_states[object->num_contained_transform_states] = i;
4797 object->num_contained_transform_states++;
4800 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4801 if(object->changed.vertexShaderConstantsF[i]) {
4802 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4803 object->num_contained_vs_consts_f++;
4806 for(i = 0; i < MAX_CONST_I; i++) {
4807 if(object->changed.vertexShaderConstantsI[i]) {
4808 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4809 object->num_contained_vs_consts_i++;
4812 for(i = 0; i < MAX_CONST_B; i++) {
4813 if(object->changed.vertexShaderConstantsB[i]) {
4814 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4815 object->num_contained_vs_consts_b++;
4818 for(i = 0; i < MAX_CONST_I; i++) {
4819 if(object->changed.pixelShaderConstantsI[i]) {
4820 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4821 object->num_contained_ps_consts_i++;
4824 for(i = 0; i < MAX_CONST_B; i++) {
4825 if(object->changed.pixelShaderConstantsB[i]) {
4826 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4827 object->num_contained_ps_consts_b++;
4830 for(i = 0; i < MAX_TEXTURES; i++) {
4831 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4832 if(object->changed.textureState[i][j]) {
4833 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4834 object->contained_tss_states[object->num_contained_tss_states].state = j;
4835 object->num_contained_tss_states++;
4839 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4840 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4841 if(object->changed.samplerState[i][j]) {
4842 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4843 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4844 object->num_contained_sampler_states++;
4849 *ppStateBlock = (IWineD3DStateBlock*) object;
4850 This->isRecordingState = FALSE;
4851 This->updateStateBlock = This->stateBlock;
4852 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4853 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4854 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4859 * Scene related functions
4861 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4862 /* At the moment we have no need for any functionality at the beginning
4864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 TRACE("(%p)\n", This);
4868 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4869 return WINED3DERR_INVALIDCALL;
4871 This->inScene = TRUE;
4875 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4877 TRACE("(%p)\n", This);
4879 if(!This->inScene) {
4880 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4881 return WINED3DERR_INVALIDCALL;
4884 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4885 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4888 checkGLcall("glFlush");
4891 This->inScene = FALSE;
4895 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4896 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4897 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4899 IWineD3DSwapChain *swapChain = NULL;
4901 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4903 TRACE("(%p) Presenting the frame\n", This);
4905 for(i = 0 ; i < swapchains ; i ++) {
4907 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4908 TRACE("presentinng chain %d, %p\n", i, swapChain);
4909 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4910 IWineD3DSwapChain_Release(swapChain);
4916 /* Not called from the VTable (internal subroutine) */
4917 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4918 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4919 float Z, DWORD Stencil) {
4920 GLbitfield glMask = 0;
4922 WINED3DRECT curRect;
4924 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4925 UINT drawable_width, drawable_height;
4926 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4928 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4929 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4930 * for the cleared parts, and the untouched parts.
4932 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4933 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4934 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4935 * checking all this if the dest surface is in the drawable anyway.
4937 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4939 if(vp->X != 0 || vp->Y != 0 ||
4940 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4941 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4944 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4945 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4946 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4947 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4948 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4951 if(Count > 0 && pRects && (
4952 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4953 pRects[0].x2 < target->currentDesc.Width ||
4954 pRects[0].y2 < target->currentDesc.Height)) {
4955 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4962 target->get_drawable_size(target, &drawable_width, &drawable_height);
4964 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4967 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
4968 apply_fbo_state((IWineD3DDevice *) This);
4971 /* Only set the values up once, as they are not changing */
4972 if (Flags & WINED3DCLEAR_STENCIL) {
4973 glClearStencil(Stencil);
4974 checkGLcall("glClearStencil");
4975 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4976 glStencilMask(0xFFFFFFFF);
4979 if (Flags & WINED3DCLEAR_ZBUFFER) {
4980 glDepthMask(GL_TRUE);
4982 checkGLcall("glClearDepth");
4983 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4984 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4986 if(This->depth_copy_state == WINED3D_DCS_COPY) {
4987 if(vp->X != 0 || vp->Y != 0 ||
4988 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4989 depth_copy((IWineD3DDevice *) This);
4991 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4992 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4993 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4994 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4995 depth_copy((IWineD3DDevice *) This);
4997 else if(Count > 0 && pRects && (
4998 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4999 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5000 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5001 depth_copy((IWineD3DDevice *) This);
5004 This->depth_copy_state = WINED3D_DCS_INITIAL;
5007 if (Flags & WINED3DCLEAR_TARGET) {
5008 TRACE("Clearing screen with glClear to color %x\n", Color);
5009 glClearColor(D3DCOLOR_R(Color),
5013 checkGLcall("glClearColor");
5015 /* Clear ALL colors! */
5016 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5017 glMask = glMask | GL_COLOR_BUFFER_BIT;
5020 vp_rect.left = vp->X;
5021 vp_rect.top = vp->Y;
5022 vp_rect.right = vp->X + vp->Width;
5023 vp_rect.bottom = vp->Y + vp->Height;
5024 if (!(Count > 0 && pRects)) {
5025 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5026 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5028 if(This->render_offscreen) {
5029 glScissor(vp_rect.left, vp_rect.top,
5030 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5032 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5033 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5035 checkGLcall("glScissor");
5037 checkGLcall("glClear");
5039 /* Now process each rect in turn */
5040 for (i = 0; i < Count; i++) {
5041 /* Note gl uses lower left, width/height */
5042 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5043 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5044 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5046 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5047 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5048 curRect.x1, (target->currentDesc.Height - curRect.y2),
5049 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5051 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5052 * The rectangle is not cleared, no error is returned, but further rectanlges are
5053 * still cleared if they are valid
5055 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5056 TRACE("Rectangle with negative dimensions, ignoring\n");
5060 if(This->render_offscreen) {
5061 glScissor(curRect.x1, curRect.y1,
5062 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5064 glScissor(curRect.x1, drawable_height - curRect.y2,
5065 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5067 checkGLcall("glScissor");
5070 checkGLcall("glClear");
5074 /* Restore the old values (why..?) */
5075 if (Flags & WINED3DCLEAR_STENCIL) {
5076 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5078 if (Flags & WINED3DCLEAR_TARGET) {
5079 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5080 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5081 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5082 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5083 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5085 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5086 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5088 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5089 /* TODO: Move the fbo logic into ModifyLocation() */
5090 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5091 target->Flags |= SFLAG_INTEXTURE;
5099 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5100 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5101 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5102 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5104 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5105 Count, pRects, Flags, Color, Z, Stencil);
5107 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5108 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5109 /* TODO: What about depth stencil buffers without stencil bits? */
5110 return WINED3DERR_INVALIDCALL;
5113 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5119 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5120 UINT PrimitiveCount) {
5122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5124 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5125 debug_d3dprimitivetype(PrimitiveType),
5126 StartVertex, PrimitiveCount);
5128 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5129 if(This->stateBlock->streamIsUP) {
5130 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5131 This->stateBlock->streamIsUP = FALSE;
5134 if(This->stateBlock->loadBaseVertexIndex != 0) {
5135 This->stateBlock->loadBaseVertexIndex = 0;
5136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5138 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5139 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5140 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5144 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5145 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5146 WINED3DPRIMITIVETYPE PrimitiveType,
5147 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5149 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5151 IWineD3DIndexBuffer *pIB;
5152 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5155 pIB = This->stateBlock->pIndexData;
5157 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5158 * without an index buffer set. (The first time at least...)
5159 * D3D8 simply dies, but I doubt it can do much harm to return
5160 * D3DERR_INVALIDCALL there as well. */
5161 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5162 return WINED3DERR_INVALIDCALL;
5165 if(This->stateBlock->streamIsUP) {
5166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5167 This->stateBlock->streamIsUP = FALSE;
5169 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5171 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5172 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5173 minIndex, NumVertices, startIndex, primCount);
5175 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5176 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5182 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5183 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5184 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5187 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5188 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5193 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5194 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5195 UINT VertexStreamZeroStride) {
5196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5197 IWineD3DVertexBuffer *vb;
5199 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5200 debug_d3dprimitivetype(PrimitiveType),
5201 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5203 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5204 vb = This->stateBlock->streamSource[0];
5205 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5206 if(vb) IWineD3DVertexBuffer_Release(vb);
5207 This->stateBlock->streamOffset[0] = 0;
5208 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5209 This->stateBlock->streamIsUP = TRUE;
5210 This->stateBlock->loadBaseVertexIndex = 0;
5212 /* TODO: Only mark dirty if drawing from a different UP address */
5213 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5215 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5216 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5218 /* MSDN specifies stream zero settings must be set to NULL */
5219 This->stateBlock->streamStride[0] = 0;
5220 This->stateBlock->streamSource[0] = NULL;
5222 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5223 * the new stream sources or use UP drawing again
5228 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5229 UINT MinVertexIndex, UINT NumVertices,
5230 UINT PrimitiveCount, CONST void* pIndexData,
5231 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5232 UINT VertexStreamZeroStride) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 IWineD3DVertexBuffer *vb;
5236 IWineD3DIndexBuffer *ib;
5238 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5239 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5240 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5241 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5243 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5249 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5250 vb = This->stateBlock->streamSource[0];
5251 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5252 if(vb) IWineD3DVertexBuffer_Release(vb);
5253 This->stateBlock->streamIsUP = TRUE;
5254 This->stateBlock->streamOffset[0] = 0;
5255 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5257 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5258 This->stateBlock->baseVertexIndex = 0;
5259 This->stateBlock->loadBaseVertexIndex = 0;
5260 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5264 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5266 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5267 This->stateBlock->streamSource[0] = NULL;
5268 This->stateBlock->streamStride[0] = 0;
5269 ib = This->stateBlock->pIndexData;
5271 IWineD3DIndexBuffer_Release(ib);
5272 This->stateBlock->pIndexData = NULL;
5274 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5275 * SetStreamSource to specify a vertex buffer
5281 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5284 /* Mark the state dirty until we have nicer tracking
5285 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5288 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5289 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5290 This->stateBlock->baseVertexIndex = 0;
5291 This->up_strided = DrawPrimStrideData;
5292 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5293 This->up_strided = NULL;
5297 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5299 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5301 /* Mark the state dirty until we have nicer tracking
5302 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5305 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5306 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5307 This->stateBlock->streamIsUP = TRUE;
5308 This->stateBlock->baseVertexIndex = 0;
5309 This->up_strided = DrawPrimStrideData;
5310 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5311 This->up_strided = NULL;
5315 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5316 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5317 * not callable by the app directly no parameter validation checks are needed here.
5319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5320 WINED3DLOCKED_BOX src;
5321 WINED3DLOCKED_BOX dst;
5323 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5325 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5326 * dirtification to improve loading performance.
5328 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5329 if(FAILED(hr)) return hr;
5330 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5332 IWineD3DVolume_UnlockBox(pSourceVolume);
5336 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5338 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5340 IWineD3DVolume_UnlockBox(pSourceVolume);
5342 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5347 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5348 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5350 HRESULT hr = WINED3D_OK;
5351 WINED3DRESOURCETYPE sourceType;
5352 WINED3DRESOURCETYPE destinationType;
5355 /* TODO: think about moving the code into IWineD3DBaseTexture */
5357 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5359 /* verify that the source and destination textures aren't NULL */
5360 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5361 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5362 This, pSourceTexture, pDestinationTexture);
5363 hr = WINED3DERR_INVALIDCALL;
5366 if (pSourceTexture == pDestinationTexture) {
5367 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5368 This, pSourceTexture, pDestinationTexture);
5369 hr = WINED3DERR_INVALIDCALL;
5371 /* Verify that the source and destination textures are the same type */
5372 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5373 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5375 if (sourceType != destinationType) {
5376 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5378 hr = WINED3DERR_INVALIDCALL;
5381 /* check that both textures have the identical numbers of levels */
5382 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5383 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5384 hr = WINED3DERR_INVALIDCALL;
5387 if (WINED3D_OK == hr) {
5389 /* Make sure that the destination texture is loaded */
5390 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5392 /* Update every surface level of the texture */
5393 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5395 switch (sourceType) {
5396 case WINED3DRTYPE_TEXTURE:
5398 IWineD3DSurface *srcSurface;
5399 IWineD3DSurface *destSurface;
5401 for (i = 0 ; i < levels ; ++i) {
5402 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5403 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5404 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5405 IWineD3DSurface_Release(srcSurface);
5406 IWineD3DSurface_Release(destSurface);
5407 if (WINED3D_OK != hr) {
5408 WARN("(%p) : Call to update surface failed\n", This);
5414 case WINED3DRTYPE_CUBETEXTURE:
5416 IWineD3DSurface *srcSurface;
5417 IWineD3DSurface *destSurface;
5418 WINED3DCUBEMAP_FACES faceType;
5420 for (i = 0 ; i < levels ; ++i) {
5421 /* Update each cube face */
5422 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5423 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5424 if (WINED3D_OK != hr) {
5425 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5427 TRACE("Got srcSurface %p\n", srcSurface);
5429 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5430 if (WINED3D_OK != hr) {
5431 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5433 TRACE("Got desrSurface %p\n", destSurface);
5435 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5436 IWineD3DSurface_Release(srcSurface);
5437 IWineD3DSurface_Release(destSurface);
5438 if (WINED3D_OK != hr) {
5439 WARN("(%p) : Call to update surface failed\n", This);
5447 case WINED3DRTYPE_VOLUMETEXTURE:
5449 IWineD3DVolume *srcVolume = NULL;
5450 IWineD3DVolume *destVolume = NULL;
5452 for (i = 0 ; i < levels ; ++i) {
5453 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5454 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5455 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5456 IWineD3DVolume_Release(srcVolume);
5457 IWineD3DVolume_Release(destVolume);
5458 if (WINED3D_OK != hr) {
5459 WARN("(%p) : Call to update volume failed\n", This);
5467 FIXME("(%p) : Unsupported source and destination type\n", This);
5468 hr = WINED3DERR_INVALIDCALL;
5475 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5476 IWineD3DSwapChain *swapChain;
5478 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5479 if(hr == WINED3D_OK) {
5480 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5481 IWineD3DSwapChain_Release(swapChain);
5486 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5487 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5488 /* return a sensible default */
5490 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5491 FIXME("(%p) : stub\n", This);
5495 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5499 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5500 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5501 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5502 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5507 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5511 PALETTEENTRY **palettes;
5513 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5515 if (PaletteNumber >= MAX_PALETTES) {
5516 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5517 return WINED3DERR_INVALIDCALL;
5520 if (PaletteNumber >= This->NumberOfPalettes) {
5521 NewSize = This->NumberOfPalettes;
5524 } while(PaletteNumber >= NewSize);
5525 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5527 ERR("Out of memory!\n");
5528 return E_OUTOFMEMORY;
5530 This->palettes = palettes;
5531 This->NumberOfPalettes = NewSize;
5534 if (!This->palettes[PaletteNumber]) {
5535 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5536 if (!This->palettes[PaletteNumber]) {
5537 ERR("Out of memory!\n");
5538 return E_OUTOFMEMORY;
5542 for (j = 0; j < 256; ++j) {
5543 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5544 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5545 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5546 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5548 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5549 TRACE("(%p) : returning\n", This);
5553 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5556 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5557 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5558 /* What happens in such situation isn't documented; Native seems to silently abort
5559 on such conditions. Return Invalid Call. */
5560 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5561 return WINED3DERR_INVALIDCALL;
5563 for (j = 0; j < 256; ++j) {
5564 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5565 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5566 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5567 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5569 TRACE("(%p) : returning\n", This);
5573 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5575 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5576 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5577 (tested with reference rasterizer). Return Invalid Call. */
5578 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5579 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5580 return WINED3DERR_INVALIDCALL;
5582 /*TODO: stateblocks */
5583 if (This->currentPalette != PaletteNumber) {
5584 This->currentPalette = PaletteNumber;
5585 dirtify_p8_texture_samplers(This);
5587 TRACE("(%p) : returning\n", This);
5591 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 if (PaletteNumber == NULL) {
5594 WARN("(%p) : returning Invalid Call\n", This);
5595 return WINED3DERR_INVALIDCALL;
5597 /*TODO: stateblocks */
5598 *PaletteNumber = This->currentPalette;
5599 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5603 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5605 static BOOL showFixmes = TRUE;
5607 FIXME("(%p) : stub\n", This);
5611 This->softwareVertexProcessing = bSoftware;
5616 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5618 static BOOL showFixmes = TRUE;
5620 FIXME("(%p) : stub\n", This);
5623 return This->softwareVertexProcessing;
5627 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5629 IWineD3DSwapChain *swapChain;
5632 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5634 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5635 if(hr == WINED3D_OK){
5636 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5637 IWineD3DSwapChain_Release(swapChain);
5639 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5645 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5647 static BOOL showfixmes = TRUE;
5648 if(nSegments != 0.0f) {
5650 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5657 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 static BOOL showfixmes = TRUE;
5661 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5667 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5668 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5669 /** TODO: remove casts to IWineD3DSurfaceImpl
5670 * NOTE: move code to surface to accomplish this
5671 ****************************************/
5672 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5673 int srcWidth, srcHeight;
5674 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5675 WINED3DFORMAT destFormat, srcFormat;
5677 int srcLeft, destLeft, destTop;
5678 WINED3DPOOL srcPool, destPool;
5680 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5681 glDescriptor *glDescription = NULL;
5684 CONVERT_TYPES convert = NO_CONVERSION;
5686 WINED3DSURFACE_DESC winedesc;
5688 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5689 memset(&winedesc, 0, sizeof(winedesc));
5690 winedesc.Width = &srcSurfaceWidth;
5691 winedesc.Height = &srcSurfaceHeight;
5692 winedesc.Pool = &srcPool;
5693 winedesc.Format = &srcFormat;
5695 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5697 winedesc.Width = &destSurfaceWidth;
5698 winedesc.Height = &destSurfaceHeight;
5699 winedesc.Pool = &destPool;
5700 winedesc.Format = &destFormat;
5701 winedesc.Size = &destSize;
5703 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5705 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5706 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5707 return WINED3DERR_INVALIDCALL;
5710 /* This call loads the opengl surface directly, instead of copying the surface to the
5711 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5712 * copy in sysmem and use regular surface loading.
5714 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5715 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5716 if(convert != NO_CONVERSION) {
5717 return IWineD3DSurface_BltFast(pDestinationSurface,
5718 pDestPoint ? pDestPoint->x : 0,
5719 pDestPoint ? pDestPoint->y : 0,
5720 pSourceSurface, (RECT *) pSourceRect, 0);
5723 if (destFormat == WINED3DFMT_UNKNOWN) {
5724 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5725 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5727 /* Get the update surface description */
5728 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5731 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5735 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5736 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5737 checkGLcall("glActiveTextureARB");
5740 /* Make sure the surface is loaded and up to date */
5741 IWineD3DSurface_PreLoad(pDestinationSurface);
5743 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5745 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5746 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5747 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5748 srcLeft = pSourceRect ? pSourceRect->left : 0;
5749 destLeft = pDestPoint ? pDestPoint->x : 0;
5750 destTop = pDestPoint ? pDestPoint->y : 0;
5753 /* This function doesn't support compressed textures
5754 the pitch is just bytesPerPixel * width */
5755 if(srcWidth != srcSurfaceWidth || srcLeft ){
5756 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5757 offset += srcLeft * pSrcSurface->bytesPerPixel;
5758 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5760 /* TODO DXT formats */
5762 if(pSourceRect != NULL && pSourceRect->top != 0){
5763 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5765 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5767 ,glDescription->level
5772 ,glDescription->glFormat
5773 ,glDescription->glType
5774 ,IWineD3DSurface_GetData(pSourceSurface)
5778 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5780 /* need to lock the surface to get the data */
5781 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5784 /* TODO: Cube and volume support */
5786 /* not a whole row so we have to do it a line at a time */
5789 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5790 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5792 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5794 glTexSubImage2D(glDescription->target
5795 ,glDescription->level
5800 ,glDescription->glFormat
5801 ,glDescription->glType
5802 ,data /* could be quicker using */
5807 } else { /* Full width, so just write out the whole texture */
5809 if (WINED3DFMT_DXT1 == destFormat ||
5810 WINED3DFMT_DXT2 == destFormat ||
5811 WINED3DFMT_DXT3 == destFormat ||
5812 WINED3DFMT_DXT4 == destFormat ||
5813 WINED3DFMT_DXT5 == destFormat) {
5814 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5815 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5816 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5817 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5818 } if (destFormat != srcFormat) {
5819 FIXME("Updating mixed format compressed texture is not curretly support\n");
5821 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5822 glDescription->level,
5823 glDescription->glFormatInternal,
5828 IWineD3DSurface_GetData(pSourceSurface));
5831 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5836 glTexSubImage2D(glDescription->target
5837 ,glDescription->level
5842 ,glDescription->glFormat
5843 ,glDescription->glType
5844 ,IWineD3DSurface_GetData(pSourceSurface)
5848 checkGLcall("glTexSubImage2D");
5852 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5858 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5860 struct WineD3DRectPatch *patch;
5864 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5866 if(!(Handle || pRectPatchInfo)) {
5867 /* TODO: Write a test for the return value, thus the FIXME */
5868 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5869 return WINED3DERR_INVALIDCALL;
5873 i = PATCHMAP_HASHFUNC(Handle);
5875 LIST_FOR_EACH(e, &This->patches[i]) {
5876 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5877 if(patch->Handle == Handle) {
5884 TRACE("Patch does not exist. Creating a new one\n");
5885 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5886 patch->Handle = Handle;
5887 list_add_head(&This->patches[i], &patch->entry);
5889 TRACE("Found existing patch %p\n", patch);
5892 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5893 * attributes we have to tesselate, read back, and draw. This needs a patch
5894 * management structure instance. Create one.
5896 * A possible improvement is to check if a vertex shader is used, and if not directly
5899 FIXME("Drawing an uncached patch. This is slow\n");
5900 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5903 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5904 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5905 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5907 TRACE("Tesselation density or patch info changed, retesselating\n");
5909 if(pRectPatchInfo) {
5910 patch->RectPatchInfo = *pRectPatchInfo;
5912 patch->numSegs[0] = pNumSegs[0];
5913 patch->numSegs[1] = pNumSegs[1];
5914 patch->numSegs[2] = pNumSegs[2];
5915 patch->numSegs[3] = pNumSegs[3];
5917 hr = tesselate_rectpatch(This, patch);
5919 WARN("Patch tesselation failed\n");
5921 /* Do not release the handle to store the params of the patch */
5923 HeapFree(GetProcessHeap(), 0, patch);
5929 This->currentPatch = patch;
5930 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5931 This->currentPatch = NULL;
5933 /* Destroy uncached patches */
5935 HeapFree(GetProcessHeap(), 0, patch->mem);
5936 HeapFree(GetProcessHeap(), 0, patch);
5941 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5943 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5944 FIXME("(%p) : Stub\n", This);
5948 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5951 struct WineD3DRectPatch *patch;
5953 TRACE("(%p) Handle(%d)\n", This, Handle);
5955 i = PATCHMAP_HASHFUNC(Handle);
5956 LIST_FOR_EACH(e, &This->patches[i]) {
5957 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5958 if(patch->Handle == Handle) {
5959 TRACE("Deleting patch %p\n", patch);
5960 list_remove(&patch->entry);
5961 HeapFree(GetProcessHeap(), 0, patch->mem);
5962 HeapFree(GetProcessHeap(), 0, patch);
5967 /* TODO: Write a test for the return value */
5968 FIXME("Attempt to destroy nonexistent patch\n");
5969 return WINED3DERR_INVALIDCALL;
5972 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
5974 IWineD3DSwapChain *swapchain;
5976 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5977 if (SUCCEEDED(hr)) {
5978 IWineD3DSwapChain_Release((IUnknown *)swapchain);
5985 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5989 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
5990 checkGLcall("glGenFramebuffersEXT()");
5992 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
5993 checkGLcall("glBindFramebuffer()");
5996 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
5997 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
5998 IWineD3DBaseTextureImpl *texture_impl;
5999 GLenum texttarget, target;
6002 texttarget = surface_impl->glDescription.target;
6003 if(texttarget == GL_TEXTURE_2D) {
6004 target = GL_TEXTURE_2D;
6005 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6006 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6007 target = GL_TEXTURE_RECTANGLE_ARB;
6008 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6010 target = GL_TEXTURE_CUBE_MAP_ARB;
6011 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6014 IWineD3DSurface_PreLoad(surface);
6016 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6017 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6018 glBindTexture(target, old_binding);
6020 /* Update base texture states array */
6021 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6022 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6023 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6024 if (texture_impl->baseTexture.bindCount) {
6025 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6028 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6031 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6032 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6034 checkGLcall("attach_surface_fbo");
6037 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6039 IWineD3DSwapChain *swapchain;
6041 swapchain = get_swapchain(surface);
6045 TRACE("Surface %p is onscreen\n", surface);
6047 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6048 buffer = surface_get_gl_buffer(surface, swapchain);
6049 glDrawBuffer(buffer);
6050 checkGLcall("glDrawBuffer()");
6052 TRACE("Surface %p is offscreen\n", surface);
6053 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6054 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6058 glEnable(GL_SCISSOR_TEST);
6060 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6062 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6063 rect->x2 - rect->x1, rect->y2 - rect->y1);
6065 checkGLcall("glScissor");
6067 glDisable(GL_SCISSOR_TEST);
6069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6071 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6072 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6074 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6075 glClear(GL_COLOR_BUFFER_BIT);
6076 checkGLcall("glClear");
6078 if (This->render_offscreen) {
6079 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6081 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6082 checkGLcall("glBindFramebuffer()");
6085 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6086 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6087 glDrawBuffer(GL_BACK);
6088 checkGLcall("glDrawBuffer()");
6092 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6093 unsigned int r, g, b, a;
6096 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6097 destfmt == WINED3DFMT_R8G8B8)
6100 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6102 a = (color & 0xff000000) >> 24;
6103 r = (color & 0x00ff0000) >> 16;
6104 g = (color & 0x0000ff00) >> 8;
6105 b = (color & 0x000000ff) >> 0;
6109 case WINED3DFMT_R5G6B5:
6110 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6117 TRACE("Returning %08x\n", ret);
6120 case WINED3DFMT_X1R5G5B5:
6121 case WINED3DFMT_A1R5G5B5:
6130 TRACE("Returning %08x\n", ret);
6134 TRACE("Returning %08x\n", a);
6137 case WINED3DFMT_X4R4G4B4:
6138 case WINED3DFMT_A4R4G4B4:
6147 TRACE("Returning %08x\n", ret);
6150 case WINED3DFMT_R3G3B2:
6157 TRACE("Returning %08x\n", ret);
6160 case WINED3DFMT_X8B8G8R8:
6161 case WINED3DFMT_A8B8G8R8:
6166 TRACE("Returning %08x\n", ret);
6169 case WINED3DFMT_A2R10G10B10:
6171 r = (r * 1024) / 256;
6172 g = (g * 1024) / 256;
6173 b = (b * 1024) / 256;
6178 TRACE("Returning %08x\n", ret);
6181 case WINED3DFMT_A2B10G10R10:
6183 r = (r * 1024) / 256;
6184 g = (g * 1024) / 256;
6185 b = (b * 1024) / 256;
6190 TRACE("Returning %08x\n", ret);
6194 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6199 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6201 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6203 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6205 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6206 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6207 return WINED3DERR_INVALIDCALL;
6210 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6212 color_fill_fbo(iface, pSurface, pRect, color);
6216 /* Just forward this to the DirectDraw blitting engine */
6217 memset(&BltFx, 0, sizeof(BltFx));
6218 BltFx.dwSize = sizeof(BltFx);
6219 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6220 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6224 /* rendertarget and depth stencil functions */
6225 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6226 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6228 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6229 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6230 return WINED3DERR_INVALIDCALL;
6233 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6234 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6235 /* Note inc ref on returned surface */
6236 if(*ppRenderTarget != NULL)
6237 IWineD3DSurface_AddRef(*ppRenderTarget);
6241 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6243 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6244 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6245 IWineD3DSwapChainImpl *Swapchain;
6248 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6250 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6251 if(hr != WINED3D_OK) {
6252 ERR("Can't get the swapchain\n");
6256 /* Make sure to release the swapchain */
6257 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6259 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6260 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6261 return WINED3DERR_INVALIDCALL;
6263 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6264 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6265 return WINED3DERR_INVALIDCALL;
6268 if(Swapchain->frontBuffer != Front) {
6269 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6271 if(Swapchain->frontBuffer)
6272 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6273 Swapchain->frontBuffer = Front;
6275 if(Swapchain->frontBuffer) {
6276 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6280 if(Back && !Swapchain->backBuffer) {
6281 /* We need memory for the back buffer array - only one back buffer this way */
6282 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6283 if(!Swapchain->backBuffer) {
6284 ERR("Out of memory\n");
6285 return E_OUTOFMEMORY;
6289 if(Swapchain->backBuffer[0] != Back) {
6290 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6292 /* What to do about the context here in the case of multithreading? Not sure.
6293 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6296 if(!Swapchain->backBuffer[0]) {
6297 /* GL was told to draw to the front buffer at creation,
6300 glDrawBuffer(GL_BACK);
6301 checkGLcall("glDrawBuffer(GL_BACK)");
6302 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6303 Swapchain->presentParms.BackBufferCount = 1;
6305 /* That makes problems - disable for now */
6306 /* glDrawBuffer(GL_FRONT); */
6307 checkGLcall("glDrawBuffer(GL_FRONT)");
6308 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6309 Swapchain->presentParms.BackBufferCount = 0;
6313 if(Swapchain->backBuffer[0])
6314 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6315 Swapchain->backBuffer[0] = Back;
6317 if(Swapchain->backBuffer[0]) {
6318 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6320 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6321 Swapchain->backBuffer = NULL;
6329 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6331 *ppZStencilSurface = This->stencilBufferTarget;
6332 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6334 if(*ppZStencilSurface != NULL) {
6335 /* Note inc ref on returned surface */
6336 IWineD3DSurface_AddRef(*ppZStencilSurface);
6339 return WINED3DERR_NOTFOUND;
6343 /* TODO: Handle stencil attachments */
6344 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6346 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6348 TRACE("Set depth stencil to %p\n", depth_stencil);
6350 if (depth_stencil_impl) {
6351 if (depth_stencil_impl->current_renderbuffer) {
6352 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6353 checkGLcall("glFramebufferRenderbufferEXT()");
6355 IWineD3DBaseTextureImpl *texture_impl;
6356 GLenum texttarget, target;
6357 GLint old_binding = 0;
6359 texttarget = depth_stencil_impl->glDescription.target;
6360 if(texttarget == GL_TEXTURE_2D) {
6361 target = GL_TEXTURE_2D;
6362 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6363 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6364 target = GL_TEXTURE_RECTANGLE_ARB;
6365 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6367 target = GL_TEXTURE_CUBE_MAP_ARB;
6368 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6371 IWineD3DSurface_PreLoad(depth_stencil);
6373 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6374 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6375 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6376 glBindTexture(target, old_binding);
6378 /* Update base texture states array */
6379 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6380 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6381 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6382 if (texture_impl->baseTexture.bindCount) {
6383 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6386 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6389 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6390 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6391 checkGLcall("glFramebufferTexture2DEXT()");
6394 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6395 checkGLcall("glFramebufferTexture2DEXT()");
6399 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6403 TRACE("Set render target %u to %p\n", idx, render_target);
6406 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6407 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6409 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6410 checkGLcall("glFramebufferTexture2DEXT()");
6412 This->draw_buffers[idx] = GL_NONE;
6416 static void check_fbo_status(IWineD3DDevice *iface) {
6417 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6420 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6421 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6422 TRACE("FBO complete\n");
6424 IWineD3DSurfaceImpl *attachment;
6426 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6428 /* Dump the FBO attachments */
6429 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6430 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6432 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6433 attachment->pow2Width, attachment->pow2Height);
6436 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6438 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6439 attachment->pow2Width, attachment->pow2Height);
6444 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6446 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6447 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6449 if (!ds_impl) return FALSE;
6451 if (ds_impl->current_renderbuffer) {
6452 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6453 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6456 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6457 rt_impl->pow2Height != ds_impl->pow2Height);
6460 void apply_fbo_state(IWineD3DDevice *iface) {
6461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6464 if (This->render_offscreen) {
6465 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6467 /* Apply render targets */
6468 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6469 IWineD3DSurface *render_target = This->render_targets[i];
6470 if (This->fbo_color_attachments[i] != render_target) {
6471 set_render_target_fbo(iface, i, render_target);
6472 This->fbo_color_attachments[i] = render_target;
6476 /* Apply depth targets */
6477 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6478 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6479 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6481 if (This->stencilBufferTarget) {
6482 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6484 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6485 This->fbo_depth_attachment = This->stencilBufferTarget;
6488 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6489 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6490 checkGLcall("glDrawBuffers()");
6492 glDrawBuffer(This->draw_buffers[0]);
6493 checkGLcall("glDrawBuffer()");
6496 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6499 check_fbo_status(iface);
6502 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6503 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6505 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6506 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6509 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6510 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6511 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6512 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6515 case WINED3DTEXF_LINEAR:
6516 gl_filter = GL_LINEAR;
6520 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6521 case WINED3DTEXF_NONE:
6522 case WINED3DTEXF_POINT:
6523 gl_filter = GL_NEAREST;
6527 /* Attach src surface to src fbo */
6528 src_swapchain = get_swapchain(src_surface);
6529 if (src_swapchain) {
6532 TRACE("Source surface %p is onscreen\n", src_surface);
6533 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6534 /* Make sure the drawable is up to date. In the offscreen case
6535 * attach_surface_fbo() implicitly takes care of this. */
6536 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6539 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6540 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6541 glReadBuffer(buffer);
6542 checkGLcall("glReadBuffer()");
6544 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6545 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6547 TRACE("Source surface %p is offscreen\n", src_surface);
6549 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6550 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6551 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6552 checkGLcall("glReadBuffer()");
6556 /* Attach dst surface to dst fbo */
6557 dst_swapchain = get_swapchain(dst_surface);
6558 if (dst_swapchain) {
6561 TRACE("Destination surface %p is onscreen\n", dst_surface);
6562 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6563 /* Make sure the drawable is up to date. In the offscreen case
6564 * attach_surface_fbo() implicitly takes care of this. */
6565 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6568 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6569 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6570 glDrawBuffer(buffer);
6571 checkGLcall("glDrawBuffer()");
6573 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6574 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6576 TRACE("Destination surface %p is offscreen\n", dst_surface);
6578 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6579 if(!src_swapchain) {
6580 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6584 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6585 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6586 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6587 checkGLcall("glDrawBuffer()");
6589 glDisable(GL_SCISSOR_TEST);
6590 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6593 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6594 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6595 checkGLcall("glBlitFramebuffer()");
6597 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6598 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6599 checkGLcall("glBlitFramebuffer()");
6602 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6604 if (This->render_offscreen) {
6605 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6607 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6608 checkGLcall("glBindFramebuffer()");
6611 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6612 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6613 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6614 glDrawBuffer(GL_BACK);
6615 checkGLcall("glDrawBuffer()");
6620 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6622 WINED3DVIEWPORT viewport;
6624 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6626 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6627 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6628 This, RenderTargetIndex, GL_LIMITS(buffers));
6629 return WINED3DERR_INVALIDCALL;
6632 /* MSDN says that null disables the render target
6633 but a device must always be associated with a render target
6634 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6636 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6637 FIXME("Trying to set render target 0 to NULL\n");
6638 return WINED3DERR_INVALIDCALL;
6640 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6641 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);
6642 return WINED3DERR_INVALIDCALL;
6645 /* If we are trying to set what we already have, don't bother */
6646 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6647 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6650 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6651 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6652 This->render_targets[RenderTargetIndex] = pRenderTarget;
6654 /* Render target 0 is special */
6655 if(RenderTargetIndex == 0) {
6656 /* Finally, reset the viewport as the MSDN states. */
6657 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6658 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6661 viewport.MaxZ = 1.0f;
6662 viewport.MinZ = 0.0f;
6663 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6664 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6665 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6669 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6671 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6672 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6674 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6679 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6681 HRESULT hr = WINED3D_OK;
6682 IWineD3DSurface *tmp;
6684 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6686 if (pNewZStencil == This->stencilBufferTarget) {
6687 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6689 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6690 * depending on the renter target implementation being used.
6691 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6692 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6693 * stencil buffer and incur an extra memory overhead
6694 ******************************************************/
6696 tmp = This->stencilBufferTarget;
6697 This->stencilBufferTarget = pNewZStencil;
6698 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6699 /* should we be calling the parent or the wined3d surface? */
6700 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6701 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6704 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6705 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6706 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6715 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6716 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6718 /* TODO: the use of Impl is deprecated. */
6719 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6720 WINED3DLOCKED_RECT lockedRect;
6722 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6724 /* some basic validation checks */
6725 if(This->cursorTexture) {
6726 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6728 glDeleteTextures(1, &This->cursorTexture);
6730 This->cursorTexture = 0;
6733 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6734 This->haveHardwareCursor = TRUE;
6736 This->haveHardwareCursor = FALSE;
6739 WINED3DLOCKED_RECT rect;
6741 /* MSDN: Cursor must be A8R8G8B8 */
6742 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6743 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6744 return WINED3DERR_INVALIDCALL;
6747 /* MSDN: Cursor must be smaller than the display mode */
6748 if(pSur->currentDesc.Width > This->ddraw_width ||
6749 pSur->currentDesc.Height > This->ddraw_height) {
6750 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);
6751 return WINED3DERR_INVALIDCALL;
6754 if (!This->haveHardwareCursor) {
6755 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6757 /* Do not store the surface's pointer because the application may
6758 * release it after setting the cursor image. Windows doesn't
6759 * addref the set surface, so we can't do this either without
6760 * creating circular refcount dependencies. Copy out the gl texture
6763 This->cursorWidth = pSur->currentDesc.Width;
6764 This->cursorHeight = pSur->currentDesc.Height;
6765 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6767 const GlPixelFormatDesc *glDesc;
6768 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6769 char *mem, *bits = (char *)rect.pBits;
6770 GLint intfmt = glDesc->glInternal;
6771 GLint format = glDesc->glFormat;
6772 GLint type = glDesc->glType;
6773 INT height = This->cursorHeight;
6774 INT width = This->cursorWidth;
6775 INT bpp = tableEntry->bpp;
6778 /* Reformat the texture memory (pitch and width can be
6780 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6781 for(i = 0; i < height; i++)
6782 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6783 IWineD3DSurface_UnlockRect(pCursorBitmap);
6786 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6787 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6788 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6791 /* Make sure that a proper texture unit is selected */
6792 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6793 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6794 checkGLcall("glActiveTextureARB");
6796 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6797 /* Create a new cursor texture */
6798 glGenTextures(1, &This->cursorTexture);
6799 checkGLcall("glGenTextures");
6800 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6801 checkGLcall("glBindTexture");
6802 /* Copy the bitmap memory into the cursor texture */
6803 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6804 HeapFree(GetProcessHeap(), 0, mem);
6805 checkGLcall("glTexImage2D");
6807 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6808 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6809 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6816 FIXME("A cursor texture was not returned.\n");
6817 This->cursorTexture = 0;
6822 /* Draw a hardware cursor */
6823 ICONINFO cursorInfo;
6825 /* Create and clear maskBits because it is not needed for
6826 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6828 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6829 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6830 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6831 WINED3DLOCK_NO_DIRTY_UPDATE |
6832 WINED3DLOCK_READONLY
6834 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6835 pSur->currentDesc.Height);
6837 cursorInfo.fIcon = FALSE;
6838 cursorInfo.xHotspot = XHotSpot;
6839 cursorInfo.yHotspot = YHotSpot;
6840 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6841 pSur->currentDesc.Height, 1,
6843 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6844 pSur->currentDesc.Height, 1,
6845 32, lockedRect.pBits);
6846 IWineD3DSurface_UnlockRect(pCursorBitmap);
6847 /* Create our cursor and clean up. */
6848 cursor = CreateIconIndirect(&cursorInfo);
6850 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6851 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6852 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6853 This->hardwareCursor = cursor;
6854 HeapFree(GetProcessHeap(), 0, maskBits);
6858 This->xHotSpot = XHotSpot;
6859 This->yHotSpot = YHotSpot;
6863 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6864 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6865 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6867 This->xScreenSpace = XScreenSpace;
6868 This->yScreenSpace = YScreenSpace;
6874 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6875 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6876 BOOL oldVisible = This->bCursorVisible;
6879 TRACE("(%p) : visible(%d)\n", This, bShow);
6882 * When ShowCursor is first called it should make the cursor appear at the OS's last
6883 * known cursor position. Because of this, some applications just repetitively call
6884 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6887 This->xScreenSpace = pt.x;
6888 This->yScreenSpace = pt.y;
6890 if (This->haveHardwareCursor) {
6891 This->bCursorVisible = bShow;
6893 SetCursor(This->hardwareCursor);
6899 if (This->cursorTexture)
6900 This->bCursorVisible = bShow;
6906 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6907 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6908 IWineD3DResourceImpl *resource;
6909 TRACE("(%p) : state (%u)\n", This, This->state);
6911 /* TODO: Implement wrapping of the WndProc so that mimimize and maxamise can be monitored and the states adjusted. */
6912 switch (This->state) {
6915 case WINED3DERR_DEVICELOST:
6917 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6918 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6919 return WINED3DERR_DEVICENOTRESET;
6921 return WINED3DERR_DEVICELOST;
6923 case WINED3DERR_DRIVERINTERNALERROR:
6924 return WINED3DERR_DRIVERINTERNALERROR;
6928 return WINED3DERR_DRIVERINTERNALERROR;
6932 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6934 /** FIXME: Resource tracking needs to be done,
6935 * The closes we can do to this is set the priorities of all managed textures low
6936 * and then reset them.
6937 ***********************************************************/
6938 FIXME("(%p) : stub\n", This);
6942 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6943 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6945 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6946 if(surface->Flags & SFLAG_DIBSECTION) {
6947 /* Release the DC */
6948 SelectObject(surface->hDC, surface->dib.holdbitmap);
6949 DeleteDC(surface->hDC);
6950 /* Release the DIB section */
6951 DeleteObject(surface->dib.DIBsection);
6952 surface->dib.bitmap_data = NULL;
6953 surface->resource.allocatedMemory = NULL;
6954 surface->Flags &= ~SFLAG_DIBSECTION;
6956 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6957 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6958 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
6959 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6960 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6962 surface->pow2Width = surface->pow2Height = 1;
6963 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6964 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6966 surface->glRect.left = 0;
6967 surface->glRect.top = 0;
6968 surface->glRect.right = surface->pow2Width;
6969 surface->glRect.bottom = surface->pow2Height;
6971 if(surface->glDescription.textureName) {
6972 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6974 glDeleteTextures(1, &surface->glDescription.textureName);
6976 surface->glDescription.textureName = 0;
6977 surface->Flags &= ~SFLAG_CLIENT;
6979 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6980 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6981 surface->Flags |= SFLAG_NONPOW2;
6983 surface->Flags &= ~SFLAG_NONPOW2;
6985 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6986 surface->resource.allocatedMemory = NULL;
6987 surface->resource.heapMemory = NULL;
6988 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6991 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6992 TRACE("Unloading resource %p\n", resource);
6993 IWineD3DResource_UnLoad(resource);
6994 IWineD3DResource_Release(resource);
6998 static void reset_fbo_state(IWineD3DDevice *iface) {
6999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7003 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7004 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7007 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7010 if (This->src_fbo) {
7011 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7014 if (This->dst_fbo) {
7015 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7018 checkGLcall("Tear down fbos\n");
7021 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7022 This->fbo_color_attachments[i] = NULL;
7024 This->fbo_depth_attachment = NULL;
7027 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7029 WINED3DDISPLAYMODE m;
7032 /* All Windowed modes are supported, as is leaving the current mode */
7033 if(pp->Windowed) return TRUE;
7034 if(!pp->BackBufferWidth) return TRUE;
7035 if(!pp->BackBufferHeight) return TRUE;
7037 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7038 for(i = 0; i < count; i++) {
7039 memset(&m, 0, sizeof(m));
7040 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7042 ERR("EnumAdapterModes failed\n");
7044 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7045 /* Mode found, it is supported */
7049 /* Mode not found -> not supported */
7053 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7055 IWineD3DSwapChainImpl *swapchain;
7057 BOOL DisplayModeChanged = FALSE;
7058 WINED3DDISPLAYMODE mode;
7059 IWineD3DBaseShaderImpl *shader;
7060 IWineD3DSurfaceImpl *target;
7062 TRACE("(%p)\n", This);
7064 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7066 ERR("Failed to get the first implicit swapchain\n");
7070 if(!is_display_mode_supported(This, pPresentationParameters)) {
7071 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7072 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7073 pPresentationParameters->BackBufferHeight);
7074 return WINED3DERR_INVALIDCALL;
7077 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7078 * on an existing gl context, so there's no real need for recreation.
7080 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7082 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7084 TRACE("New params:\n");
7085 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7086 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7087 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7088 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7089 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7090 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7091 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7092 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7093 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7094 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7095 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7096 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7097 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7099 /* No special treatment of these parameters. Just store them */
7100 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7101 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7102 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7103 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7105 /* What to do about these? */
7106 if(pPresentationParameters->BackBufferCount != 0 &&
7107 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7108 ERR("Cannot change the back buffer count yet\n");
7110 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7111 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7112 ERR("Cannot change the back buffer format yet\n");
7114 if(pPresentationParameters->hDeviceWindow != NULL &&
7115 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7116 ERR("Cannot change the device window yet\n");
7118 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7119 ERR("What do do about a changed auto depth stencil parameter?\n");
7122 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7123 reset_fbo_state((IWineD3DDevice *) This);
7126 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7127 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7128 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7132 if(This->depth_blt_texture) {
7133 glDeleteTextures(1, &This->depth_blt_texture);
7134 This->depth_blt_texture = 0;
7136 This->shader_backend->shader_destroy_depth_blt(iface);
7137 This->shader_backend->shader_free_private(iface);
7139 for (i = 0; i < GL_LIMITS(textures); i++) {
7140 /* Textures are recreated below */
7141 glDeleteTextures(1, &This->dummyTextureName[i]);
7142 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7143 This->dummyTextureName[i] = 0;
7147 while(This->numContexts) {
7148 DestroyContext(This, This->contexts[0]);
7150 This->activeContext = NULL;
7151 HeapFree(GetProcessHeap(), 0, swapchain->context);
7152 swapchain->context = NULL;
7153 swapchain->num_contexts = 0;
7155 if(pPresentationParameters->Windowed) {
7156 mode.Width = swapchain->orig_width;
7157 mode.Height = swapchain->orig_height;
7158 mode.RefreshRate = 0;
7159 mode.Format = swapchain->presentParms.BackBufferFormat;
7161 mode.Width = pPresentationParameters->BackBufferWidth;
7162 mode.Height = pPresentationParameters->BackBufferHeight;
7163 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7164 mode.Format = swapchain->presentParms.BackBufferFormat;
7167 /* Should Width == 800 && Height == 0 set 800x600? */
7168 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7169 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7170 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7177 vp.Width = pPresentationParameters->BackBufferWidth;
7178 vp.Height = pPresentationParameters->BackBufferHeight;
7182 if(!pPresentationParameters->Windowed) {
7183 DisplayModeChanged = TRUE;
7185 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7186 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7188 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7189 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7190 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7192 if(This->auto_depth_stencil_buffer) {
7193 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7197 /* Now set the new viewport */
7198 IWineD3DDevice_SetViewport(iface, &vp);
7201 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7202 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7203 DisplayModeChanged) {
7205 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7206 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7207 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7208 } else if(!pPresentationParameters->Windowed) {
7209 DWORD style = This->style, exStyle = This->exStyle;
7210 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7211 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7212 * Reset to clear up their mess. Guild Wars also loses the device during that.
7216 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7217 This->style = style;
7218 This->exStyle = exStyle;
7221 /* Recreate the primary swapchain's context */
7222 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7223 if(swapchain->backBuffer) {
7224 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7226 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7228 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7229 &swapchain->presentParms);
7230 swapchain->num_contexts = 1;
7231 This->activeContext = swapchain->context[0];
7232 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7234 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7236 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7238 create_dummy_textures(This);
7241 hr = This->shader_backend->shader_alloc_private(iface);
7243 ERR("Failed to recreate shader private data\n");
7247 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7253 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7255 /** FIXME: always true at the moment **/
7256 if(!bEnableDialogs) {
7257 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7263 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7265 TRACE("(%p) : pParameters %p\n", This, pParameters);
7267 *pParameters = This->createParms;
7271 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7272 IWineD3DSwapChain *swapchain;
7273 HRESULT hrc = WINED3D_OK;
7275 TRACE("Relaying to swapchain\n");
7277 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7278 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7279 IWineD3DSwapChain_Release(swapchain);
7284 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7285 IWineD3DSwapChain *swapchain;
7286 HRESULT hrc = WINED3D_OK;
7288 TRACE("Relaying to swapchain\n");
7290 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7291 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7292 IWineD3DSwapChain_Release(swapchain);
7298 /** ********************************************************
7299 * Notification functions
7300 ** ********************************************************/
7301 /** This function must be called in the release of a resource when ref == 0,
7302 * the contents of resource must still be correct,
7303 * any handles to other resource held by the caller must be closed
7304 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7305 *****************************************************/
7306 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7309 TRACE("(%p) : Adding Resource %p\n", This, resource);
7310 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7313 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7316 TRACE("(%p) : Removing resource %p\n", This, resource);
7318 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7322 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7326 TRACE("(%p) : resource %p\n", This, resource);
7327 switch(IWineD3DResource_GetType(resource)){
7328 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7329 case WINED3DRTYPE_SURFACE: {
7332 /* Cleanup any FBO attachments if d3d is enabled */
7333 if(This->d3d_initialized) {
7334 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7335 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7337 TRACE("Last active render target destroyed\n");
7338 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7339 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7340 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7341 * and the lastActiveRenderTarget member shouldn't matter
7344 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7345 TRACE("Activating primary back buffer\n");
7346 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7347 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7348 /* Single buffering environment */
7349 TRACE("Activating primary front buffer\n");
7350 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7352 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7353 /* Implicit render target destroyed, that means the device is being destroyed
7354 * whatever we set here, it shouldn't matter
7356 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7359 /* May happen during ddraw uninitialization */
7360 TRACE("Render target set, but swapchain does not exist!\n");
7361 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7365 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7366 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7367 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7368 set_render_target_fbo(iface, i, NULL);
7369 This->fbo_color_attachments[i] = NULL;
7372 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7373 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7374 set_depth_stencil_fbo(iface, NULL);
7375 This->fbo_depth_attachment = NULL;
7381 case WINED3DRTYPE_TEXTURE:
7382 case WINED3DRTYPE_CUBETEXTURE:
7383 case WINED3DRTYPE_VOLUMETEXTURE:
7384 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7385 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7386 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7387 This->stateBlock->textures[counter] = NULL;
7389 if (This->updateStateBlock != This->stateBlock ){
7390 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7391 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7392 This->updateStateBlock->textures[counter] = NULL;
7397 case WINED3DRTYPE_VOLUME:
7398 /* TODO: nothing really? */
7400 case WINED3DRTYPE_VERTEXBUFFER:
7401 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7404 TRACE("Cleaning up stream pointers\n");
7406 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7407 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7408 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7410 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7411 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7412 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7413 This->updateStateBlock->streamSource[streamNumber] = 0;
7414 /* Set changed flag? */
7417 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) */
7418 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7419 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7420 This->stateBlock->streamSource[streamNumber] = 0;
7423 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7424 else { /* This shouldn't happen */
7425 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7432 case WINED3DRTYPE_INDEXBUFFER:
7433 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7434 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7435 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7436 This->updateStateBlock->pIndexData = NULL;
7439 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7440 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7441 This->stateBlock->pIndexData = NULL;
7447 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7452 /* Remove the resource from the resourceStore */
7453 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7455 TRACE("Resource released\n");
7459 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7461 IWineD3DResourceImpl *resource, *cursor;
7463 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7465 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7466 TRACE("enumerating resource %p\n", resource);
7467 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7468 ret = pCallback((IWineD3DResource *) resource, pData);
7469 if(ret == S_FALSE) {
7470 TRACE("Canceling enumeration\n");
7477 /**********************************************************
7478 * IWineD3DDevice VTbl follows
7479 **********************************************************/
7481 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7483 /*** IUnknown methods ***/
7484 IWineD3DDeviceImpl_QueryInterface,
7485 IWineD3DDeviceImpl_AddRef,
7486 IWineD3DDeviceImpl_Release,
7487 /*** IWineD3DDevice methods ***/
7488 IWineD3DDeviceImpl_GetParent,
7489 /*** Creation methods**/
7490 IWineD3DDeviceImpl_CreateVertexBuffer,
7491 IWineD3DDeviceImpl_CreateIndexBuffer,
7492 IWineD3DDeviceImpl_CreateStateBlock,
7493 IWineD3DDeviceImpl_CreateSurface,
7494 IWineD3DDeviceImpl_CreateTexture,
7495 IWineD3DDeviceImpl_CreateVolumeTexture,
7496 IWineD3DDeviceImpl_CreateVolume,
7497 IWineD3DDeviceImpl_CreateCubeTexture,
7498 IWineD3DDeviceImpl_CreateQuery,
7499 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7500 IWineD3DDeviceImpl_CreateVertexDeclaration,
7501 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7502 IWineD3DDeviceImpl_CreateVertexShader,
7503 IWineD3DDeviceImpl_CreatePixelShader,
7504 IWineD3DDeviceImpl_CreatePalette,
7505 /*** Odd functions **/
7506 IWineD3DDeviceImpl_Init3D,
7507 IWineD3DDeviceImpl_Uninit3D,
7508 IWineD3DDeviceImpl_SetFullscreen,
7509 IWineD3DDeviceImpl_SetMultithreaded,
7510 IWineD3DDeviceImpl_EvictManagedResources,
7511 IWineD3DDeviceImpl_GetAvailableTextureMem,
7512 IWineD3DDeviceImpl_GetBackBuffer,
7513 IWineD3DDeviceImpl_GetCreationParameters,
7514 IWineD3DDeviceImpl_GetDeviceCaps,
7515 IWineD3DDeviceImpl_GetDirect3D,
7516 IWineD3DDeviceImpl_GetDisplayMode,
7517 IWineD3DDeviceImpl_SetDisplayMode,
7518 IWineD3DDeviceImpl_GetHWND,
7519 IWineD3DDeviceImpl_SetHWND,
7520 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7521 IWineD3DDeviceImpl_GetRasterStatus,
7522 IWineD3DDeviceImpl_GetSwapChain,
7523 IWineD3DDeviceImpl_Reset,
7524 IWineD3DDeviceImpl_SetDialogBoxMode,
7525 IWineD3DDeviceImpl_SetCursorProperties,
7526 IWineD3DDeviceImpl_SetCursorPosition,
7527 IWineD3DDeviceImpl_ShowCursor,
7528 IWineD3DDeviceImpl_TestCooperativeLevel,
7529 /*** Getters and setters **/
7530 IWineD3DDeviceImpl_SetClipPlane,
7531 IWineD3DDeviceImpl_GetClipPlane,
7532 IWineD3DDeviceImpl_SetClipStatus,
7533 IWineD3DDeviceImpl_GetClipStatus,
7534 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7535 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7536 IWineD3DDeviceImpl_SetDepthStencilSurface,
7537 IWineD3DDeviceImpl_GetDepthStencilSurface,
7538 IWineD3DDeviceImpl_SetFVF,
7539 IWineD3DDeviceImpl_GetFVF,
7540 IWineD3DDeviceImpl_SetGammaRamp,
7541 IWineD3DDeviceImpl_GetGammaRamp,
7542 IWineD3DDeviceImpl_SetIndices,
7543 IWineD3DDeviceImpl_GetIndices,
7544 IWineD3DDeviceImpl_SetBaseVertexIndex,
7545 IWineD3DDeviceImpl_GetBaseVertexIndex,
7546 IWineD3DDeviceImpl_SetLight,
7547 IWineD3DDeviceImpl_GetLight,
7548 IWineD3DDeviceImpl_SetLightEnable,
7549 IWineD3DDeviceImpl_GetLightEnable,
7550 IWineD3DDeviceImpl_SetMaterial,
7551 IWineD3DDeviceImpl_GetMaterial,
7552 IWineD3DDeviceImpl_SetNPatchMode,
7553 IWineD3DDeviceImpl_GetNPatchMode,
7554 IWineD3DDeviceImpl_SetPaletteEntries,
7555 IWineD3DDeviceImpl_GetPaletteEntries,
7556 IWineD3DDeviceImpl_SetPixelShader,
7557 IWineD3DDeviceImpl_GetPixelShader,
7558 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7559 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7560 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7561 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7562 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7563 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7564 IWineD3DDeviceImpl_SetRenderState,
7565 IWineD3DDeviceImpl_GetRenderState,
7566 IWineD3DDeviceImpl_SetRenderTarget,
7567 IWineD3DDeviceImpl_GetRenderTarget,
7568 IWineD3DDeviceImpl_SetFrontBackBuffers,
7569 IWineD3DDeviceImpl_SetSamplerState,
7570 IWineD3DDeviceImpl_GetSamplerState,
7571 IWineD3DDeviceImpl_SetScissorRect,
7572 IWineD3DDeviceImpl_GetScissorRect,
7573 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7574 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7575 IWineD3DDeviceImpl_SetStreamSource,
7576 IWineD3DDeviceImpl_GetStreamSource,
7577 IWineD3DDeviceImpl_SetStreamSourceFreq,
7578 IWineD3DDeviceImpl_GetStreamSourceFreq,
7579 IWineD3DDeviceImpl_SetTexture,
7580 IWineD3DDeviceImpl_GetTexture,
7581 IWineD3DDeviceImpl_SetTextureStageState,
7582 IWineD3DDeviceImpl_GetTextureStageState,
7583 IWineD3DDeviceImpl_SetTransform,
7584 IWineD3DDeviceImpl_GetTransform,
7585 IWineD3DDeviceImpl_SetVertexDeclaration,
7586 IWineD3DDeviceImpl_GetVertexDeclaration,
7587 IWineD3DDeviceImpl_SetVertexShader,
7588 IWineD3DDeviceImpl_GetVertexShader,
7589 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7590 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7591 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7592 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7593 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7594 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7595 IWineD3DDeviceImpl_SetViewport,
7596 IWineD3DDeviceImpl_GetViewport,
7597 IWineD3DDeviceImpl_MultiplyTransform,
7598 IWineD3DDeviceImpl_ValidateDevice,
7599 IWineD3DDeviceImpl_ProcessVertices,
7600 /*** State block ***/
7601 IWineD3DDeviceImpl_BeginStateBlock,
7602 IWineD3DDeviceImpl_EndStateBlock,
7603 /*** Scene management ***/
7604 IWineD3DDeviceImpl_BeginScene,
7605 IWineD3DDeviceImpl_EndScene,
7606 IWineD3DDeviceImpl_Present,
7607 IWineD3DDeviceImpl_Clear,
7609 IWineD3DDeviceImpl_DrawPrimitive,
7610 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7611 IWineD3DDeviceImpl_DrawPrimitiveUP,
7612 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7613 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7614 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7615 IWineD3DDeviceImpl_DrawRectPatch,
7616 IWineD3DDeviceImpl_DrawTriPatch,
7617 IWineD3DDeviceImpl_DeletePatch,
7618 IWineD3DDeviceImpl_ColorFill,
7619 IWineD3DDeviceImpl_UpdateTexture,
7620 IWineD3DDeviceImpl_UpdateSurface,
7621 IWineD3DDeviceImpl_GetFrontBufferData,
7622 /*** object tracking ***/
7623 IWineD3DDeviceImpl_ResourceReleased,
7624 IWineD3DDeviceImpl_EnumResources
7627 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7629 /*** IUnknown methods ***/
7630 IWineD3DDeviceImpl_QueryInterface,
7631 IWineD3DDeviceImpl_AddRef,
7632 IWineD3DDeviceImpl_Release,
7633 /*** IWineD3DDevice methods ***/
7634 IWineD3DDeviceImpl_GetParent,
7635 /*** Creation methods**/
7636 IWineD3DDeviceImpl_CreateVertexBuffer,
7637 IWineD3DDeviceImpl_CreateIndexBuffer,
7638 IWineD3DDeviceImpl_CreateStateBlock,
7639 IWineD3DDeviceImpl_CreateSurface,
7640 IWineD3DDeviceImpl_CreateTexture,
7641 IWineD3DDeviceImpl_CreateVolumeTexture,
7642 IWineD3DDeviceImpl_CreateVolume,
7643 IWineD3DDeviceImpl_CreateCubeTexture,
7644 IWineD3DDeviceImpl_CreateQuery,
7645 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7646 IWineD3DDeviceImpl_CreateVertexDeclaration,
7647 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7648 IWineD3DDeviceImpl_CreateVertexShader,
7649 IWineD3DDeviceImpl_CreatePixelShader,
7650 IWineD3DDeviceImpl_CreatePalette,
7651 /*** Odd functions **/
7652 IWineD3DDeviceImpl_Init3D,
7653 IWineD3DDeviceImpl_Uninit3D,
7654 IWineD3DDeviceImpl_SetFullscreen,
7655 IWineD3DDeviceImpl_SetMultithreaded,
7656 IWineD3DDeviceImpl_EvictManagedResources,
7657 IWineD3DDeviceImpl_GetAvailableTextureMem,
7658 IWineD3DDeviceImpl_GetBackBuffer,
7659 IWineD3DDeviceImpl_GetCreationParameters,
7660 IWineD3DDeviceImpl_GetDeviceCaps,
7661 IWineD3DDeviceImpl_GetDirect3D,
7662 IWineD3DDeviceImpl_GetDisplayMode,
7663 IWineD3DDeviceImpl_SetDisplayMode,
7664 IWineD3DDeviceImpl_GetHWND,
7665 IWineD3DDeviceImpl_SetHWND,
7666 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7667 IWineD3DDeviceImpl_GetRasterStatus,
7668 IWineD3DDeviceImpl_GetSwapChain,
7669 IWineD3DDeviceImpl_Reset,
7670 IWineD3DDeviceImpl_SetDialogBoxMode,
7671 IWineD3DDeviceImpl_SetCursorProperties,
7672 IWineD3DDeviceImpl_SetCursorPosition,
7673 IWineD3DDeviceImpl_ShowCursor,
7674 IWineD3DDeviceImpl_TestCooperativeLevel,
7675 /*** Getters and setters **/
7676 IWineD3DDeviceImpl_SetClipPlane,
7677 IWineD3DDeviceImpl_GetClipPlane,
7678 IWineD3DDeviceImpl_SetClipStatus,
7679 IWineD3DDeviceImpl_GetClipStatus,
7680 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7681 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7682 IWineD3DDeviceImpl_SetDepthStencilSurface,
7683 IWineD3DDeviceImpl_GetDepthStencilSurface,
7684 IWineD3DDeviceImpl_SetFVF,
7685 IWineD3DDeviceImpl_GetFVF,
7686 IWineD3DDeviceImpl_SetGammaRamp,
7687 IWineD3DDeviceImpl_GetGammaRamp,
7688 IWineD3DDeviceImpl_SetIndices,
7689 IWineD3DDeviceImpl_GetIndices,
7690 IWineD3DDeviceImpl_SetBaseVertexIndex,
7691 IWineD3DDeviceImpl_GetBaseVertexIndex,
7692 IWineD3DDeviceImpl_SetLight,
7693 IWineD3DDeviceImpl_GetLight,
7694 IWineD3DDeviceImpl_SetLightEnable,
7695 IWineD3DDeviceImpl_GetLightEnable,
7696 IWineD3DDeviceImpl_SetMaterial,
7697 IWineD3DDeviceImpl_GetMaterial,
7698 IWineD3DDeviceImpl_SetNPatchMode,
7699 IWineD3DDeviceImpl_GetNPatchMode,
7700 IWineD3DDeviceImpl_SetPaletteEntries,
7701 IWineD3DDeviceImpl_GetPaletteEntries,
7702 IWineD3DDeviceImpl_SetPixelShader,
7703 IWineD3DDeviceImpl_GetPixelShader,
7704 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7705 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7706 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7707 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7708 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7709 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7710 IWineD3DDeviceImpl_SetRenderState,
7711 IWineD3DDeviceImpl_GetRenderState,
7712 IWineD3DDeviceImpl_SetRenderTarget,
7713 IWineD3DDeviceImpl_GetRenderTarget,
7714 IWineD3DDeviceImpl_SetFrontBackBuffers,
7715 IWineD3DDeviceImpl_SetSamplerState,
7716 IWineD3DDeviceImpl_GetSamplerState,
7717 IWineD3DDeviceImpl_SetScissorRect,
7718 IWineD3DDeviceImpl_GetScissorRect,
7719 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7720 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7721 IWineD3DDeviceImpl_SetStreamSource,
7722 IWineD3DDeviceImpl_GetStreamSource,
7723 IWineD3DDeviceImpl_SetStreamSourceFreq,
7724 IWineD3DDeviceImpl_GetStreamSourceFreq,
7725 IWineD3DDeviceImpl_SetTexture,
7726 IWineD3DDeviceImpl_GetTexture,
7727 IWineD3DDeviceImpl_SetTextureStageState,
7728 IWineD3DDeviceImpl_GetTextureStageState,
7729 IWineD3DDeviceImpl_SetTransform,
7730 IWineD3DDeviceImpl_GetTransform,
7731 IWineD3DDeviceImpl_SetVertexDeclaration,
7732 IWineD3DDeviceImpl_GetVertexDeclaration,
7733 IWineD3DDeviceImpl_SetVertexShader,
7734 IWineD3DDeviceImpl_GetVertexShader,
7735 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7736 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7737 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7738 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7739 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7740 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7741 IWineD3DDeviceImpl_SetViewport,
7742 IWineD3DDeviceImpl_GetViewport,
7743 IWineD3DDeviceImpl_MultiplyTransform,
7744 IWineD3DDeviceImpl_ValidateDevice,
7745 IWineD3DDeviceImpl_ProcessVertices,
7746 /*** State block ***/
7747 IWineD3DDeviceImpl_BeginStateBlock,
7748 IWineD3DDeviceImpl_EndStateBlock,
7749 /*** Scene management ***/
7750 IWineD3DDeviceImpl_BeginScene,
7751 IWineD3DDeviceImpl_EndScene,
7752 IWineD3DDeviceImpl_Present,
7753 IWineD3DDeviceImpl_Clear,
7755 IWineD3DDeviceImpl_DrawPrimitive,
7756 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7757 IWineD3DDeviceImpl_DrawPrimitiveUP,
7758 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7759 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7760 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7761 IWineD3DDeviceImpl_DrawRectPatch,
7762 IWineD3DDeviceImpl_DrawTriPatch,
7763 IWineD3DDeviceImpl_DeletePatch,
7764 IWineD3DDeviceImpl_ColorFill,
7765 IWineD3DDeviceImpl_UpdateTexture,
7766 IWineD3DDeviceImpl_UpdateSurface,
7767 IWineD3DDeviceImpl_GetFrontBufferData,
7768 /*** object tracking ***/
7769 IWineD3DDeviceImpl_ResourceReleased,
7770 IWineD3DDeviceImpl_EnumResources
7773 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7774 WINED3DRS_ALPHABLENDENABLE ,
7775 WINED3DRS_ALPHAFUNC ,
7776 WINED3DRS_ALPHAREF ,
7777 WINED3DRS_ALPHATESTENABLE ,
7779 WINED3DRS_COLORWRITEENABLE ,
7780 WINED3DRS_DESTBLEND ,
7781 WINED3DRS_DITHERENABLE ,
7782 WINED3DRS_FILLMODE ,
7783 WINED3DRS_FOGDENSITY ,
7785 WINED3DRS_FOGSTART ,
7786 WINED3DRS_LASTPIXEL ,
7787 WINED3DRS_SHADEMODE ,
7788 WINED3DRS_SRCBLEND ,
7789 WINED3DRS_STENCILENABLE ,
7790 WINED3DRS_STENCILFAIL ,
7791 WINED3DRS_STENCILFUNC ,
7792 WINED3DRS_STENCILMASK ,
7793 WINED3DRS_STENCILPASS ,
7794 WINED3DRS_STENCILREF ,
7795 WINED3DRS_STENCILWRITEMASK ,
7796 WINED3DRS_STENCILZFAIL ,
7797 WINED3DRS_TEXTUREFACTOR ,
7808 WINED3DRS_ZWRITEENABLE
7811 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7812 WINED3DTSS_ADDRESSW ,
7813 WINED3DTSS_ALPHAARG0 ,
7814 WINED3DTSS_ALPHAARG1 ,
7815 WINED3DTSS_ALPHAARG2 ,
7816 WINED3DTSS_ALPHAOP ,
7817 WINED3DTSS_BUMPENVLOFFSET ,
7818 WINED3DTSS_BUMPENVLSCALE ,
7819 WINED3DTSS_BUMPENVMAT00 ,
7820 WINED3DTSS_BUMPENVMAT01 ,
7821 WINED3DTSS_BUMPENVMAT10 ,
7822 WINED3DTSS_BUMPENVMAT11 ,
7823 WINED3DTSS_COLORARG0 ,
7824 WINED3DTSS_COLORARG1 ,
7825 WINED3DTSS_COLORARG2 ,
7826 WINED3DTSS_COLOROP ,
7827 WINED3DTSS_RESULTARG ,
7828 WINED3DTSS_TEXCOORDINDEX ,
7829 WINED3DTSS_TEXTURETRANSFORMFLAGS
7832 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7833 WINED3DSAMP_ADDRESSU ,
7834 WINED3DSAMP_ADDRESSV ,
7835 WINED3DSAMP_ADDRESSW ,
7836 WINED3DSAMP_BORDERCOLOR ,
7837 WINED3DSAMP_MAGFILTER ,
7838 WINED3DSAMP_MINFILTER ,
7839 WINED3DSAMP_MIPFILTER ,
7840 WINED3DSAMP_MIPMAPLODBIAS ,
7841 WINED3DSAMP_MAXMIPLEVEL ,
7842 WINED3DSAMP_MAXANISOTROPY ,
7843 WINED3DSAMP_SRGBTEXTURE ,
7844 WINED3DSAMP_ELEMENTINDEX
7847 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7849 WINED3DRS_AMBIENTMATERIALSOURCE ,
7850 WINED3DRS_CLIPPING ,
7851 WINED3DRS_CLIPPLANEENABLE ,
7852 WINED3DRS_COLORVERTEX ,
7853 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7854 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7855 WINED3DRS_FOGDENSITY ,
7857 WINED3DRS_FOGSTART ,
7858 WINED3DRS_FOGTABLEMODE ,
7859 WINED3DRS_FOGVERTEXMODE ,
7860 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7861 WINED3DRS_LIGHTING ,
7862 WINED3DRS_LOCALVIEWER ,
7863 WINED3DRS_MULTISAMPLEANTIALIAS ,
7864 WINED3DRS_MULTISAMPLEMASK ,
7865 WINED3DRS_NORMALIZENORMALS ,
7866 WINED3DRS_PATCHEDGESTYLE ,
7867 WINED3DRS_POINTSCALE_A ,
7868 WINED3DRS_POINTSCALE_B ,
7869 WINED3DRS_POINTSCALE_C ,
7870 WINED3DRS_POINTSCALEENABLE ,
7871 WINED3DRS_POINTSIZE ,
7872 WINED3DRS_POINTSIZE_MAX ,
7873 WINED3DRS_POINTSIZE_MIN ,
7874 WINED3DRS_POINTSPRITEENABLE ,
7875 WINED3DRS_RANGEFOGENABLE ,
7876 WINED3DRS_SPECULARMATERIALSOURCE ,
7877 WINED3DRS_TWEENFACTOR ,
7878 WINED3DRS_VERTEXBLEND ,
7879 WINED3DRS_CULLMODE ,
7883 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7884 WINED3DTSS_TEXCOORDINDEX ,
7885 WINED3DTSS_TEXTURETRANSFORMFLAGS
7888 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7889 WINED3DSAMP_DMAPOFFSET
7892 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7893 DWORD rep = This->shader_backend->StateTable[state].representative;
7897 WineD3DContext *context;
7900 for(i = 0; i < This->numContexts; i++) {
7901 context = This->contexts[i];
7902 if(isStateDirty(context, rep)) continue;
7904 context->dirtyArray[context->numDirtyEntries++] = rep;
7907 context->isStateDirty[idx] |= (1 << shift);
7911 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7912 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7913 /* The drawable size of a pbuffer render target is the current pbuffer size
7915 *width = dev->pbufferWidth;
7916 *height = dev->pbufferHeight;
7919 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7920 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7922 *width = This->pow2Width;
7923 *height = This->pow2Height;
7926 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7927 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7928 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7929 * current context's drawable, which is the size of the back buffer of the swapchain
7930 * the active context belongs to. The back buffer of the swapchain is stored as the
7931 * surface the context belongs to.
7933 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7934 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;