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 usable 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;
666 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
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 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
794 object->baseTexture.minMipLookup = &minMipLookup;
795 object->baseTexture.magLookup = &magLookup;
797 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
798 object->baseTexture.magLookup = &magLookup_noFilter;
801 /** Non-power2 support **/
802 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
806 /* Find the nearest pow2 match */
807 pow2Width = pow2Height = 1;
808 while (pow2Width < Width) pow2Width <<= 1;
809 while (pow2Height < Height) pow2Height <<= 1;
811 if(pow2Width != Width || pow2Height != Height) {
813 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
814 HeapFree(GetProcessHeap(), 0, object);
816 return WINED3DERR_INVALIDCALL;
823 /** FIXME: add support for real non-power-two if it's provided by the video card **/
824 /* Precalculated scaling for 'faked' non power of two texture coords.
825 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
826 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
827 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
829 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
830 (Width != pow2Width || Height != pow2Height) &&
831 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
833 object->baseTexture.pow2Matrix[0] = (float)Width;
834 object->baseTexture.pow2Matrix[5] = (float)Height;
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_RECTANGLE_ARB;
839 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
840 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
841 object->baseTexture.pow2Matrix[10] = 1.0;
842 object->baseTexture.pow2Matrix[15] = 1.0;
843 object->target = GL_TEXTURE_2D;
845 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
847 /* Calculate levels for mip mapping */
848 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
849 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
850 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
851 return WINED3DERR_INVALIDCALL;
854 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL;
857 object->baseTexture.levels = 1;
858 } else if (Levels == 0) {
859 TRACE("calculating levels %d\n", object->baseTexture.levels);
860 object->baseTexture.levels++;
863 while (tmpW > 1 || tmpH > 1) {
864 tmpW = max(1, tmpW >> 1);
865 tmpH = max(1, tmpH >> 1);
866 object->baseTexture.levels++;
868 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
871 /* Generate all the surfaces */
874 for (i = 0; i < object->baseTexture.levels; i++)
876 /* use the callback to create the texture surface */
877 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
878 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
879 FIXME("Failed to create surface %p\n", object);
881 object->surfaces[i] = NULL;
882 IWineD3DTexture_Release((IWineD3DTexture *)object);
888 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
889 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
890 /* calculate the next mipmap level */
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
894 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
896 TRACE("(%p) : Created texture %p\n", This, object);
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
901 UINT Width, UINT Height, UINT Depth,
902 UINT Levels, DWORD Usage,
903 WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DVolumeTexture **ppVolumeTexture,
905 HANDLE *pSharedHandle, IUnknown *parent,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 IWineD3DVolumeTextureImpl *object;
914 const GlPixelFormatDesc *glDesc;
916 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN >= Format) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
922 return WINED3DERR_INVALIDCALL;
924 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
926 return WINED3DERR_INVALIDCALL;
929 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
930 D3DINITIALIZEBASETEXTURE(object->baseTexture);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
935 object->width = Width;
936 object->height = Height;
937 object->depth = Depth;
939 /* Is NP2 support for volumes needed? */
940 object->baseTexture.pow2Matrix[ 0] = 1.0;
941 object->baseTexture.pow2Matrix[ 5] = 1.0;
942 object->baseTexture.pow2Matrix[10] = 1.0;
943 object->baseTexture.pow2Matrix[15] = 1.0;
945 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
946 object->baseTexture.minMipLookup = &minMipLookup;
947 object->baseTexture.magLookup = &magLookup;
949 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
950 object->baseTexture.magLookup = &magLookup_noFilter;
953 /* Calculate levels for mip mapping */
954 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL;
964 } else if (Levels == 0) {
965 object->baseTexture.levels++;
969 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
970 tmpW = max(1, tmpW >> 1);
971 tmpH = max(1, tmpH >> 1);
972 tmpD = max(1, tmpD >> 1);
973 object->baseTexture.levels++;
975 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
978 /* Generate all the surfaces */
983 for (i = 0; i < object->baseTexture.levels; i++)
986 /* Create the volume */
987 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
988 &object->volumes[i], pSharedHandle);
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
993 *ppVolumeTexture = NULL;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1000 /* calculate the next mipmap level */
1001 tmpW = max(1, tmpW >> 1);
1002 tmpH = max(1, tmpH >> 1);
1003 tmpD = max(1, tmpD >> 1);
1005 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1007 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1008 TRACE("(%p) : Created volume texture %p\n", This, object);
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1013 UINT Width, UINT Height, UINT Depth,
1015 WINED3DFORMAT Format, WINED3DPOOL Pool,
1016 IWineD3DVolume** ppVolume,
1017 HANDLE* pSharedHandle, IUnknown *parent) {
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1025 return WINED3DERR_INVALIDCALL;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1031 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1033 object->currentDesc.Width = Width;
1034 object->currentDesc.Height = Height;
1035 object->currentDesc.Depth = Depth;
1036 object->bytesPerPixel = formatDesc->bpp;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object->lockable = TRUE;
1040 object->locked = FALSE;
1041 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1042 object->dirty = TRUE;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1048 UINT Levels, DWORD Usage,
1049 WINED3DFORMAT Format, WINED3DPOOL Pool,
1050 IWineD3DCubeTexture **ppCubeTexture,
1051 HANDLE *pSharedHandle, IUnknown *parent,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int pow2EdgeLength = EdgeLength;
1060 const GlPixelFormatDesc *glDesc;
1061 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1063 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
1064 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
1065 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
1066 return WINED3DERR_INVALIDCALL;
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN >= Format) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This);
1078 return WINED3DERR_INVALIDCALL;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1082 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084 TRACE("(%p) Create Cube Texture\n", This);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1090 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092 object->edgeLength = EdgeLength;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = &minMipLookup;
1102 object->baseTexture.magLookup = &magLookup;
1104 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1105 object->baseTexture.magLookup = &magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1142 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1143 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1145 if(hr!= WINED3D_OK) {
1149 for (l = 0; l < j; l++) {
1150 IWineD3DSurface_Release(object->surfaces[l][i]);
1152 for (k = 0; k < i; k++) {
1153 for (l = 0; l < 6; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][k]);
1158 FIXME("(%p) Failed to create surface\n",object);
1159 HeapFree(GetProcessHeap(),0,object);
1160 *ppCubeTexture = NULL;
1163 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1164 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1166 tmpW = max(1, tmpW >> 1);
1168 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1170 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1171 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1175 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 const IWineD3DQueryVtbl *vtable;
1181 /* Just a check to see if we support this type of query */
1183 case WINED3DQUERYTYPE_OCCLUSION:
1184 TRACE("(%p) occlusion query\n", This);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable = &IWineD3DOcclusionQuery_Vtbl;
1193 case WINED3DQUERYTYPE_EVENT:
1194 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1200 vtable = &IWineD3DEventQuery_Vtbl;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable = &IWineD3DQuery_Vtbl;
1219 FIXME("(%p) Unhandled query type %d\n", This, Type);
1221 if(NULL == ppQuery || hr != WINED3D_OK) {
1225 D3DCREATEOBJECTINSTANCE(object, Query)
1226 object->lpVtbl = vtable;
1227 object->type = Type;
1228 object->state = QUERY_CREATED;
1229 /* allocated the 'extended' data based on the type of query requested */
1231 case WINED3DQUERYTYPE_OCCLUSION:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1233 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1240 case WINED3DQUERYTYPE_EVENT:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1242 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(APPLE_FENCE)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1249 checkGLcall("glGenFencesNV");
1253 case WINED3DQUERYTYPE_VCACHE:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1255 case WINED3DQUERYTYPE_VERTEXSTATS:
1256 case WINED3DQUERYTYPE_TIMESTAMP:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1266 object->extendedData = 0;
1267 FIXME("(%p) Unhandled query type %d\n",This , Type);
1269 TRACE("(%p) : Created Query %p\n", This, object);
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG fullscreen_style(LONG orig_style) {
1285 LONG style = orig_style;
1286 style &= ~WS_CAPTION;
1287 style &= ~WS_THICKFRAME;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style |= WS_POPUP | WS_SYSMENU;
1295 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1296 LONG exStyle = orig_exStyle;
1298 /* Filter out window decorations */
1299 exStyle &= ~WS_EX_WINDOWEDGE;
1300 exStyle &= ~WS_EX_CLIENTEDGE;
1305 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 LONG style, exStyle;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1313 if (This->style || This->exStyle) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This, window);
1318 /* Get the parameters and save them */
1319 style = GetWindowLongW(window, GWL_STYLE);
1320 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1321 This->style = style;
1322 This->exStyle = exStyle;
1324 style = fullscreen_style(style);
1325 exStyle = fullscreen_exStyle(exStyle);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This->style, This->exStyle, style, exStyle);
1330 SetWindowLongW(window, GWL_STYLE, style);
1331 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window, HWND_TOP, 0, 0,
1335 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1336 ShowWindow(window, SW_NORMAL);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 LONG style, exStyle;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This->style && !This->exStyle) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This, window, This->style, This->exStyle);
1362 style = GetWindowLongW(window, GWL_STYLE);
1363 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style == fullscreen_style(This->style) &&
1370 exStyle == fullscreen_style(This->exStyle)) {
1371 SetWindowLongW(window, GWL_STYLE, This->style);
1372 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1375 /* Delete the old values */
1379 /* Inform the window about the update */
1380 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1393 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr = WINED3D_OK;
1395 IUnknown *bufferParent;
1396 BOOL displaymode_set = FALSE;
1397 WINED3DDISPLAYMODE Mode;
1398 const StaticPixelFormatDesc *formatDesc;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1410 return WINED3DERR_INVALIDCALL;
1411 } else if (pPresentationParameters->BackBufferCount > 1) {
1412 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");
1415 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object->win_handle = pPresentationParameters->hDeviceWindow;
1423 if (!object->win_handle) {
1424 object->win_handle = This->createParms.hFocusWindow;
1426 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1428 hDc = GetDC(object->win_handle);
1429 TRACE("Using hDc %p\n", hDc);
1432 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1433 return WINED3DERR_NOTAVAILABLE;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1438 object->orig_width = Mode.Width;
1439 object->orig_height = Mode.Height;
1440 object->orig_fmt = Mode.Format;
1441 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters->Windowed &&
1449 ((pPresentationParameters->BackBufferWidth == 0) ||
1450 (pPresentationParameters->BackBufferHeight == 0) ||
1451 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1454 GetClientRect(object->win_handle, &Rect);
1456 if (pPresentationParameters->BackBufferWidth == 0) {
1457 pPresentationParameters->BackBufferWidth = Rect.right;
1458 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1460 if (pPresentationParameters->BackBufferHeight == 0) {
1461 pPresentationParameters->BackBufferHeight = Rect.bottom;
1462 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1464 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1465 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object->presentParms = *pPresentationParameters;
1474 TRACE("calling rendertarget CB\n");
1475 hr = D3DCB_CreateRenderTarget(This->parent,
1477 object->presentParms.BackBufferWidth,
1478 object->presentParms.BackBufferHeight,
1479 object->presentParms.BackBufferFormat,
1480 object->presentParms.MultiSampleType,
1481 object->presentParms.MultiSampleQuality,
1482 TRUE /* Lockable */,
1483 &object->frontBuffer,
1484 NULL /* pShared (always null)*/);
1485 if (object->frontBuffer != NULL) {
1486 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1487 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1489 ERR("Failed to create the front buffer\n");
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters->Windowed) {
1504 WINED3DDISPLAYMODE mode;
1507 /* Change the display settings */
1508 mode.Width = pPresentationParameters->BackBufferWidth;
1509 mode.Height = pPresentationParameters->BackBufferHeight;
1510 mode.Format = pPresentationParameters->BackBufferFormat;
1511 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1513 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1514 displaymode_set = TRUE;
1515 IWineD3DDevice_SetFullscreen(iface, TRUE);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1528 if(!object->context)
1529 return E_OUTOFMEMORY;
1530 object->num_contexts = 1;
1532 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1533 if (!object->context[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr = WINED3DERR_NOTAVAILABLE;
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object->win_handle, object->context[0]->glCtx);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object->presentParms.BackBufferCount > 0) {
1548 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1549 if(!object->backBuffer) {
1550 ERR("Out of memory\n");
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr = D3DCB_CreateRenderTarget(This->parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.BackBufferFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 TRUE /* Lockable */,
1565 &object->backBuffer[i],
1566 NULL /* pShared (always null)*/);
1567 if(hr == WINED3D_OK && object->backBuffer[i]) {
1568 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1570 ERR("Cannot create new back buffer\n");
1574 glDrawBuffer(GL_BACK);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1579 object->backBuffer = NULL;
1581 /* Single buffering - draw to front buffer */
1583 glDrawBuffer(GL_FRONT);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This->auto_depth_stencil_buffer == NULL ) {
1592 hr = D3DCB_CreateDepthStencil(This->parent,
1594 object->presentParms.BackBufferWidth,
1595 object->presentParms.BackBufferHeight,
1596 object->presentParms.AutoDepthStencilFormat,
1597 object->presentParms.MultiSampleType,
1598 object->presentParms.MultiSampleQuality,
1599 FALSE /* FIXME: Discard */,
1600 &This->auto_depth_stencil_buffer,
1601 NULL /* pShared (always null)*/ );
1602 if (This->auto_depth_stencil_buffer != NULL)
1603 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object->wantsDepthStencilBuffer = TRUE;
1611 object->wantsDepthStencilBuffer = FALSE;
1614 TRACE("Created swapchain %p\n", object);
1615 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1619 if (displaymode_set) {
1623 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1626 /* Change the display settings */
1627 memset(&devmode, 0, sizeof(devmode));
1628 devmode.dmSize = sizeof(devmode);
1629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1630 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1631 devmode.dmPelsWidth = object->orig_width;
1632 devmode.dmPelsHeight = object->orig_height;
1633 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1636 if (object->backBuffer) {
1638 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1639 if(object->backBuffer[i]) {
1640 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1641 IUnknown_Release(bufferParent); /* once for the get parent */
1642 if (IUnknown_Release(bufferParent) > 0) {
1643 FIXME("(%p) Something's still holding the back buffer\n",This);
1647 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1648 object->backBuffer = NULL;
1650 if(object->context[0])
1651 DestroyContext(This, object->context[0]);
1652 if(object->frontBuffer) {
1653 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1654 IUnknown_Release(bufferParent); /* once for the get parent */
1655 if (IUnknown_Release(bufferParent) > 0) {
1656 FIXME("(%p) Something's still holding the front buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object);
1663 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1664 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1666 TRACE("(%p)\n", This);
1668 return This->NumberOfSwapChains;
1671 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1673 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1675 if(iSwapChain < This->NumberOfSwapChains) {
1676 *pSwapChain = This->swapchains[iSwapChain];
1677 IWineD3DSwapChain_AddRef(*pSwapChain);
1678 TRACE("(%p) returning %p\n", This, *pSwapChain);
1681 TRACE("Swapchain out of range\n");
1683 return WINED3DERR_INVALIDCALL;
1688 * Vertex Declaration
1690 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1691 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1693 IWineD3DVertexDeclarationImpl *object = NULL;
1694 HRESULT hr = WINED3D_OK;
1696 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1697 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1699 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1701 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1703 *ppVertexDeclaration = NULL;
1704 HeapFree(GetProcessHeap(), 0, object);
1710 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1711 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1713 unsigned int idx, idx2;
1714 unsigned int offset;
1715 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1716 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1717 BOOL has_blend_idx = has_blend &&
1718 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1719 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1720 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1721 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1722 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1723 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1724 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1726 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1727 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1729 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1730 WINED3DVERTEXELEMENT *elements = NULL;
1733 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1734 if (has_blend_idx) num_blends--;
1736 /* Compute declaration size */
1737 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1738 has_psize + has_diffuse + has_specular + num_textures + 1;
1740 /* convert the declaration */
1741 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1745 elements[size-1] = end_element;
1748 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1749 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1750 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1754 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1756 elements[idx].UsageIndex = 0;
1759 if (has_blend && (num_blends > 0)) {
1760 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1761 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1765 elements[idx].UsageIndex = 0;
1768 if (has_blend_idx) {
1769 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1770 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1771 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1772 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1777 elements[idx].UsageIndex = 0;
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1782 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1783 elements[idx].UsageIndex = 0;
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1789 elements[idx].UsageIndex = 0;
1793 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1794 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1795 elements[idx].UsageIndex = 0;
1799 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1800 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1801 elements[idx].UsageIndex = 1;
1804 for (idx2 = 0; idx2 < num_textures; idx2++) {
1805 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1806 switch (numcoords) {
1807 case WINED3DFVF_TEXTUREFORMAT1:
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 case WINED3DFVF_TEXTUREFORMAT2:
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1813 case WINED3DFVF_TEXTUREFORMAT3:
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1816 case WINED3DFVF_TEXTUREFORMAT4:
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1820 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1821 elements[idx].UsageIndex = idx2;
1825 /* Now compute offsets, and initialize the rest of the fields */
1826 for (idx = 0, offset = 0; idx < size-1; idx++) {
1827 elements[idx].Stream = 0;
1828 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1829 elements[idx].Offset = offset;
1830 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1833 *ppVertexElements = elements;
1837 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1838 WINED3DVERTEXELEMENT* elements = NULL;
1839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1843 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1844 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1846 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1847 HeapFree(GetProcessHeap(), 0, elements);
1848 if (hr != S_OK) return hr;
1853 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1855 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1856 HRESULT hr = WINED3D_OK;
1857 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1858 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1860 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1862 if (vertex_declaration) {
1863 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1866 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1868 if (WINED3D_OK != hr) {
1869 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1870 IWineD3DVertexShader_Release(*ppVertexShader);
1871 return WINED3DERR_INVALIDCALL;
1873 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1878 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1881 HRESULT hr = WINED3D_OK;
1883 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1884 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1885 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1886 if (WINED3D_OK == hr) {
1887 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1888 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1890 WARN("(%p) : Failed to create pixel shader\n", This);
1896 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1898 IWineD3DPaletteImpl *object;
1900 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1902 /* Create the new object */
1903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1905 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1906 return E_OUTOFMEMORY;
1909 object->lpVtbl = &IWineD3DPalette_Vtbl;
1911 object->Flags = Flags;
1912 object->parent = Parent;
1913 object->wineD3DDevice = This;
1914 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1916 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1919 HeapFree( GetProcessHeap(), 0, object);
1920 return E_OUTOFMEMORY;
1923 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1925 IWineD3DPalette_Release((IWineD3DPalette *) object);
1929 *Palette = (IWineD3DPalette *) object;
1934 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1938 HDC dcb = NULL, dcs = NULL;
1939 WINEDDCOLORKEY colorkey;
1941 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1944 GetObjectA(hbm, sizeof(BITMAP), &bm);
1945 dcb = CreateCompatibleDC(NULL);
1947 SelectObject(dcb, hbm);
1951 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1952 * couldn't be loaded
1954 memset(&bm, 0, sizeof(bm));
1959 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1960 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1961 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1963 ERR("Wine logo requested, but failed to create surface\n");
1968 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1969 if(FAILED(hr)) goto out;
1970 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1971 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1973 colorkey.dwColorSpaceLowValue = 0;
1974 colorkey.dwColorSpaceHighValue = 0;
1975 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1977 /* Fill the surface with a white color to show that wined3d is there */
1978 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1991 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1993 /* Under DirectX you can have texture stage operations even if no texture is
1994 bound, whereas opengl will only do texture operations when a valid texture is
1995 bound. We emulate this by creating dummy textures and binding them to each
1996 texture stage, but disable all stages by default. Hence if a stage is enabled
1997 then the default texture will kick in until replaced by a SetTexture call */
2000 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2001 /* The dummy texture does not have client storage backing */
2002 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2003 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2005 for (i = 0; i < GL_LIMITS(textures); i++) {
2006 GLubyte white = 255;
2008 /* Make appropriate texture active */
2009 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2010 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2011 checkGLcall("glActiveTextureARB");
2013 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2016 /* Generate an opengl texture name */
2017 glGenTextures(1, &This->dummyTextureName[i]);
2018 checkGLcall("glGenTextures");
2019 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2021 /* Generate a dummy 2d texture (not using 1d because they cause many
2022 * DRI drivers fall back to sw) */
2023 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2024 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2025 checkGLcall("glBindTexture");
2027 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2028 checkGLcall("glTexImage2D");
2030 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2031 /* Reenable because if supported it is enabled by default */
2032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2039 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2041 IWineD3DSwapChainImpl *swapchain = NULL;
2046 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2047 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2048 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2050 /* TODO: Test if OpenGL is compiled in and loaded */
2052 TRACE("(%p) : Creating stateblock\n", This);
2053 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2054 hr = IWineD3DDevice_CreateStateBlock(iface,
2056 (IWineD3DStateBlock **)&This->stateBlock,
2058 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2059 WARN("Failed to create stateblock\n");
2062 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2063 This->updateStateBlock = This->stateBlock;
2064 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2066 hr = allocate_shader_constants(This->updateStateBlock);
2067 if (WINED3D_OK != hr) {
2071 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2072 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2073 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2075 This->NumberOfPalettes = 1;
2076 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2077 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2078 ERR("Out of memory!\n");
2081 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2082 if(!This->palettes[0]) {
2083 ERR("Out of memory!\n");
2086 for (i = 0; i < 256; ++i) {
2087 This->palettes[0][i].peRed = 0xFF;
2088 This->palettes[0][i].peGreen = 0xFF;
2089 This->palettes[0][i].peBlue = 0xFF;
2090 This->palettes[0][i].peFlags = 0xFF;
2092 This->currentPalette = 0;
2094 /* Initialize the texture unit mapping to a 1:1 mapping */
2095 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2096 if (state < GL_LIMITS(fragment_samplers)) {
2097 This->texUnitMap[state] = state;
2098 This->rev_tex_unit_map[state] = state;
2100 This->texUnitMap[state] = -1;
2101 This->rev_tex_unit_map[state] = -1;
2105 /* Setup the implicit swapchain */
2106 TRACE("Creating implicit swapchain\n");
2107 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2108 if (FAILED(hr) || !swapchain) {
2109 WARN("Failed to create implicit swapchain\n");
2113 This->NumberOfSwapChains = 1;
2114 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2115 if(!This->swapchains) {
2116 ERR("Out of memory!\n");
2119 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2121 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2122 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2123 This->render_targets[0] = swapchain->backBuffer[0];
2124 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2127 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2128 This->render_targets[0] = swapchain->frontBuffer;
2129 This->lastActiveRenderTarget = swapchain->frontBuffer;
2131 IWineD3DSurface_AddRef(This->render_targets[0]);
2132 This->activeContext = swapchain->context[0];
2133 This->lastThread = GetCurrentThreadId();
2135 /* Depth Stencil support */
2136 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2137 if (NULL != This->stencilBufferTarget) {
2138 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2141 hr = This->shader_backend->shader_alloc_private(iface);
2143 TRACE("Shader private data couldn't be allocated\n");
2147 /* Set up some starting GL setup */
2149 /* Setup all the devices defaults */
2150 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2151 create_dummy_textures(This);
2156 IWineD3DImpl_CheckGraphicsMemory();
2159 { /* Set a default viewport */
2163 vp.Width = pPresentationParameters->BackBufferWidth;
2164 vp.Height = pPresentationParameters->BackBufferHeight;
2167 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2170 /* Initialize the current view state */
2171 This->view_ident = 1;
2172 This->contexts[0]->last_was_rhw = 0;
2173 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2174 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2176 switch(wined3d_settings.offscreen_rendering_mode) {
2179 This->offscreenBuffer = GL_BACK;
2182 case ORM_BACKBUFFER:
2184 if(This->activeContext->aux_buffers > 0) {
2185 TRACE("Using auxilliary buffer for offscreen rendering\n");
2186 This->offscreenBuffer = GL_AUX0;
2188 TRACE("Using back buffer for offscreen rendering\n");
2189 This->offscreenBuffer = GL_BACK;
2194 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2197 /* Clear the screen */
2198 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2199 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2202 This->d3d_initialized = TRUE;
2204 if(wined3d_settings.logo) {
2205 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2207 This->highest_dirty_ps_const = 0;
2208 This->highest_dirty_vs_const = 0;
2212 This->shader_backend->shader_free_private(iface);
2213 HeapFree(GetProcessHeap(), 0, This->render_targets);
2214 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2215 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2216 HeapFree(GetProcessHeap(), 0, This->swapchains);
2217 This->NumberOfSwapChains = 0;
2218 if(This->palettes) {
2219 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2220 HeapFree(GetProcessHeap(), 0, This->palettes);
2222 This->NumberOfPalettes = 0;
2224 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2226 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2227 if(This->stateBlock) {
2228 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2229 This->stateBlock = NULL;
2234 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2238 TRACE("(%p)\n", This);
2240 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2242 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2243 * it was created. Thus make sure a context is active for the glDelete* calls
2245 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2247 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2249 TRACE("Deleting high order patches\n");
2250 for(i = 0; i < PATCHMAP_SIZE; i++) {
2251 struct list *e1, *e2;
2252 struct WineD3DRectPatch *patch;
2253 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2254 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2255 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2259 /* Delete the palette conversion shader if it is around */
2260 if(This->paletteConversionShader) {
2262 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2264 This->paletteConversionShader = 0;
2267 /* Delete the pbuffer context if there is any */
2268 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2270 /* Delete the mouse cursor texture */
2271 if(This->cursorTexture) {
2273 glDeleteTextures(1, &This->cursorTexture);
2275 This->cursorTexture = 0;
2278 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2279 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2281 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2282 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2285 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2286 * private data, it might contain opengl pointers
2288 if(This->depth_blt_texture) {
2289 glDeleteTextures(1, &This->depth_blt_texture);
2290 This->depth_blt_texture = 0;
2292 This->shader_backend->shader_destroy_depth_blt(iface);
2293 This->shader_backend->shader_free_private(iface);
2295 /* Release the update stateblock */
2296 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2297 if(This->updateStateBlock != This->stateBlock)
2298 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2300 This->updateStateBlock = NULL;
2302 { /* because were not doing proper internal refcounts releasing the primary state block
2303 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2304 to set this->stateBlock = NULL; first */
2305 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2306 This->stateBlock = NULL;
2308 /* Release the stateblock */
2309 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2310 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2314 /* Release the buffers (with sanity checks)*/
2315 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2316 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2317 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2318 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2320 This->stencilBufferTarget = NULL;
2322 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2323 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2324 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2326 TRACE("Setting rendertarget to NULL\n");
2327 This->render_targets[0] = NULL;
2329 if (This->auto_depth_stencil_buffer) {
2330 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2331 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2333 This->auto_depth_stencil_buffer = NULL;
2336 for(i=0; i < This->NumberOfSwapChains; i++) {
2337 TRACE("Releasing the implicit swapchain %d\n", i);
2338 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2339 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2343 HeapFree(GetProcessHeap(), 0, This->swapchains);
2344 This->swapchains = NULL;
2345 This->NumberOfSwapChains = 0;
2347 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2348 HeapFree(GetProcessHeap(), 0, This->palettes);
2349 This->palettes = NULL;
2350 This->NumberOfPalettes = 0;
2352 HeapFree(GetProcessHeap(), 0, This->render_targets);
2353 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2354 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2355 This->render_targets = NULL;
2356 This->fbo_color_attachments = NULL;
2357 This->draw_buffers = NULL;
2359 This->d3d_initialized = FALSE;
2363 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2365 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2367 /* Setup the window for fullscreen mode */
2368 if(fullscreen && !This->ddraw_fullscreen) {
2369 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2370 } else if(!fullscreen && This->ddraw_fullscreen) {
2371 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2374 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2375 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2376 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2379 This->ddraw_fullscreen = fullscreen;
2382 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2383 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2384 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2386 * There is no way to deactivate thread safety once it is enabled.
2388 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2391 /*For now just store the flag(needed in case of ddraw) */
2392 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2397 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2401 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2404 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2406 /* Resize the screen even without a window:
2407 * The app could have unset it with SetCooperativeLevel, but not called
2408 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2409 * but we don't have any hwnd
2412 memset(&devmode, 0, sizeof(devmode));
2413 devmode.dmSize = sizeof(devmode);
2414 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2415 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2416 devmode.dmPelsWidth = pMode->Width;
2417 devmode.dmPelsHeight = pMode->Height;
2419 devmode.dmDisplayFrequency = pMode->RefreshRate;
2420 if (pMode->RefreshRate != 0) {
2421 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2424 /* Only change the mode if necessary */
2425 if( (This->ddraw_width == pMode->Width) &&
2426 (This->ddraw_height == pMode->Height) &&
2427 (This->ddraw_format == pMode->Format) &&
2428 (pMode->RefreshRate == 0) ) {
2432 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2433 if (ret != DISP_CHANGE_SUCCESSFUL) {
2434 if(devmode.dmDisplayFrequency != 0) {
2435 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2436 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2437 devmode.dmDisplayFrequency = 0;
2438 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2440 if(ret != DISP_CHANGE_SUCCESSFUL) {
2441 return WINED3DERR_NOTAVAILABLE;
2445 /* Store the new values */
2446 This->ddraw_width = pMode->Width;
2447 This->ddraw_height = pMode->Height;
2448 This->ddraw_format = pMode->Format;
2450 /* Only do this with a window of course, and only if we're fullscreened */
2451 if(This->ddraw_window && This->ddraw_fullscreen)
2452 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2454 /* And finally clip mouse to our screen */
2455 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2456 ClipCursor(&clip_rc);
2461 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2463 *ppD3D= This->wineD3D;
2464 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2465 IWineD3D_AddRef(*ppD3D);
2469 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2472 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2473 (This->adapter->TextureRam/(1024*1024)),
2474 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2475 /* return simulated texture memory left */
2476 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2484 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 /* Update the current state block */
2488 This->updateStateBlock->changed.fvf = TRUE;
2490 if(This->updateStateBlock->fvf == fvf) {
2491 TRACE("Application is setting the old fvf over, nothing to do\n");
2495 This->updateStateBlock->fvf = fvf;
2496 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2497 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2502 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2505 *pfvf = This->stateBlock->fvf;
2510 * Get / Set Stream Source
2512 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2514 IWineD3DVertexBuffer *oldSrc;
2516 if (StreamNumber >= MAX_STREAMS) {
2517 WARN("Stream out of range %d\n", StreamNumber);
2518 return WINED3DERR_INVALIDCALL;
2519 } else if(OffsetInBytes & 0x3) {
2520 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2521 return WINED3DERR_INVALIDCALL;
2524 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2525 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2527 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2529 if(oldSrc == pStreamData &&
2530 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2531 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2532 TRACE("Application is setting the old values over, nothing to do\n");
2536 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2538 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2539 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2542 /* Handle recording of state blocks */
2543 if (This->isRecordingState) {
2544 TRACE("Recording... not performing anything\n");
2545 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2546 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2550 /* Need to do a getParent and pass the references up */
2551 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2552 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2553 so for now, just count internally */
2554 if (pStreamData != NULL) {
2555 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2556 InterlockedIncrement(&vbImpl->bindCount);
2557 IWineD3DVertexBuffer_AddRef(pStreamData);
2559 if (oldSrc != NULL) {
2560 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2561 IWineD3DVertexBuffer_Release(oldSrc);
2564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2569 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2572 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2573 This->stateBlock->streamSource[StreamNumber],
2574 This->stateBlock->streamOffset[StreamNumber],
2575 This->stateBlock->streamStride[StreamNumber]);
2577 if (StreamNumber >= MAX_STREAMS) {
2578 WARN("Stream out of range %d\n", StreamNumber);
2579 return WINED3DERR_INVALIDCALL;
2581 *pStream = This->stateBlock->streamSource[StreamNumber];
2582 *pStride = This->stateBlock->streamStride[StreamNumber];
2584 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2587 if (*pStream != NULL) {
2588 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2593 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2594 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2595 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2596 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2598 /* Verify input at least in d3d9 this is invalid*/
2599 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2600 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2603 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2604 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2605 return WINED3DERR_INVALIDCALL;
2608 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2609 return WINED3DERR_INVALIDCALL;
2612 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2613 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2615 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2616 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2618 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2619 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2620 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2626 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2630 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2632 TRACE("(%p) : returning %d\n", This, *Divider);
2638 * Get / Set & Multiply Transform
2640 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2641 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2643 /* Most of this routine, comments included copied from ddraw tree initially: */
2644 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2646 /* Handle recording of state blocks */
2647 if (This->isRecordingState) {
2648 TRACE("Recording... not performing anything\n");
2649 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2650 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2655 * If the new matrix is the same as the current one,
2656 * we cut off any further processing. this seems to be a reasonable
2657 * optimization because as was noticed, some apps (warcraft3 for example)
2658 * tend towards setting the same matrix repeatedly for some reason.
2660 * From here on we assume that the new matrix is different, wherever it matters.
2662 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2663 TRACE("The app is setting the same matrix over again\n");
2666 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2670 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2671 where ViewMat = Camera space, WorldMat = world space.
2673 In OpenGL, camera and world space is combined into GL_MODELVIEW
2674 matrix. The Projection matrix stay projection matrix.
2677 /* Capture the times we can just ignore the change for now */
2678 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2679 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2680 /* Handled by the state manager */
2683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2689 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2690 *pMatrix = This->stateBlock->transforms[State];
2694 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2695 WINED3DMATRIX *mat = NULL;
2698 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2699 * below means it will be recorded in a state block change, but it
2700 * works regardless where it is recorded.
2701 * If this is found to be wrong, change to StateBlock.
2703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2706 if (State < HIGHEST_TRANSFORMSTATE)
2708 mat = &This->updateStateBlock->transforms[State];
2710 FIXME("Unhandled transform state!!\n");
2713 multiply_matrix(&temp, mat, pMatrix);
2715 /* Apply change via set transform - will reapply to eg. lights this way */
2716 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2722 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2723 you can reference any indexes you want as long as that number max are enabled at any
2724 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2725 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2726 but when recording, just build a chain pretty much of commands to be replayed. */
2728 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2730 PLIGHTINFOEL *object = NULL;
2731 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2735 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2737 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2741 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2742 return WINED3DERR_INVALIDCALL;
2745 switch(pLight->Type) {
2746 case WINED3DLIGHT_POINT:
2747 case WINED3DLIGHT_SPOT:
2748 case WINED3DLIGHT_PARALLELPOINT:
2749 case WINED3DLIGHT_GLSPOT:
2750 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2753 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2754 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2755 return WINED3DERR_INVALIDCALL;
2759 case WINED3DLIGHT_DIRECTIONAL:
2760 /* Ignores attenuation */
2764 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2765 return WINED3DERR_INVALIDCALL;
2768 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2769 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2770 if(object->OriginalIndex == Index) break;
2775 TRACE("Adding new light\n");
2776 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2778 ERR("Out of memory error when allocating a light\n");
2779 return E_OUTOFMEMORY;
2781 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2782 object->glIndex = -1;
2783 object->OriginalIndex = Index;
2784 object->changed = TRUE;
2787 /* Initialize the object */
2788 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,
2789 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2790 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2791 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2792 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2793 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2794 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2796 /* Save away the information */
2797 object->OriginalParms = *pLight;
2799 switch (pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2802 object->lightPosn[0] = pLight->Position.x;
2803 object->lightPosn[1] = pLight->Position.y;
2804 object->lightPosn[2] = pLight->Position.z;
2805 object->lightPosn[3] = 1.0f;
2806 object->cutoff = 180.0f;
2810 case WINED3DLIGHT_DIRECTIONAL:
2812 object->lightPosn[0] = -pLight->Direction.x;
2813 object->lightPosn[1] = -pLight->Direction.y;
2814 object->lightPosn[2] = -pLight->Direction.z;
2815 object->lightPosn[3] = 0.0;
2816 object->exponent = 0.0f;
2817 object->cutoff = 180.0f;
2820 case WINED3DLIGHT_SPOT:
2822 object->lightPosn[0] = pLight->Position.x;
2823 object->lightPosn[1] = pLight->Position.y;
2824 object->lightPosn[2] = pLight->Position.z;
2825 object->lightPosn[3] = 1.0;
2828 object->lightDirn[0] = pLight->Direction.x;
2829 object->lightDirn[1] = pLight->Direction.y;
2830 object->lightDirn[2] = pLight->Direction.z;
2831 object->lightDirn[3] = 1.0;
2834 * opengl-ish and d3d-ish spot lights use too different models for the
2835 * light "intensity" as a function of the angle towards the main light direction,
2836 * so we only can approximate very roughly.
2837 * however spot lights are rather rarely used in games (if ever used at all).
2838 * furthermore if still used, probably nobody pays attention to such details.
2840 if (pLight->Falloff == 0) {
2841 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2842 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2843 * will always be 1.0 for both of them, and we don't have to care for the
2844 * rest of the rather complex calculation
2846 object->exponent = 0;
2848 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2849 if (rho < 0.0001) rho = 0.0001f;
2850 object->exponent = -0.3/log(cos(rho/2));
2852 if (object->exponent > 128.0) {
2853 object->exponent = 128.0;
2855 object->cutoff = pLight->Phi*90/M_PI;
2861 FIXME("Unrecognized light type %d\n", pLight->Type);
2864 /* Update the live definitions if the light is currently assigned a glIndex */
2865 if (object->glIndex != -1 && !This->isRecordingState) {
2866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2871 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2872 PLIGHTINFOEL *lightInfo = NULL;
2873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2874 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2876 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2878 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2879 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2880 if(lightInfo->OriginalIndex == Index) break;
2884 if (lightInfo == NULL) {
2885 TRACE("Light information requested but light not defined\n");
2886 return WINED3DERR_INVALIDCALL;
2889 *pLight = lightInfo->OriginalParms;
2894 * Get / Set Light Enable
2895 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2897 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2898 PLIGHTINFOEL *lightInfo = NULL;
2899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2900 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2902 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2904 /* Tests show true = 128...not clear why */
2905 Enable = Enable? 128: 0;
2907 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2908 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2909 if(lightInfo->OriginalIndex == Index) break;
2912 TRACE("Found light: %p\n", lightInfo);
2914 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2915 if (lightInfo == NULL) {
2917 TRACE("Light enabled requested but light not defined, so defining one!\n");
2918 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2920 /* Search for it again! Should be fairly quick as near head of list */
2921 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2922 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2923 if(lightInfo->OriginalIndex == Index) break;
2926 if (lightInfo == NULL) {
2927 FIXME("Adding default lights has failed dismally\n");
2928 return WINED3DERR_INVALIDCALL;
2932 lightInfo->enabledChanged = TRUE;
2934 if(lightInfo->glIndex != -1) {
2935 if(!This->isRecordingState) {
2936 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2939 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2940 lightInfo->glIndex = -1;
2942 TRACE("Light already disabled, nothing to do\n");
2944 lightInfo->enabled = FALSE;
2946 lightInfo->enabled = TRUE;
2947 if (lightInfo->glIndex != -1) {
2949 TRACE("Nothing to do as light was enabled\n");
2952 /* Find a free gl light */
2953 for(i = 0; i < This->maxConcurrentLights; i++) {
2954 if(This->stateBlock->activeLights[i] == NULL) {
2955 This->stateBlock->activeLights[i] = lightInfo;
2956 lightInfo->glIndex = i;
2960 if(lightInfo->glIndex == -1) {
2961 /* Our tests show that Windows returns D3D_OK in this situation, even with
2962 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2963 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2964 * as well for those lights.
2966 * TODO: Test how this affects rendering
2968 FIXME("Too many concurrently active lights\n");
2972 /* i == lightInfo->glIndex */
2973 if(!This->isRecordingState) {
2974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2982 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2984 PLIGHTINFOEL *lightInfo = NULL;
2985 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2987 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2988 TRACE("(%p) : for idx(%d)\n", This, Index);
2990 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2991 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2992 if(lightInfo->OriginalIndex == Index) break;
2996 if (lightInfo == NULL) {
2997 TRACE("Light enabled state requested but light not defined\n");
2998 return WINED3DERR_INVALIDCALL;
3000 /* true is 128 according to SetLightEnable */
3001 *pEnable = lightInfo->enabled ? 128 : 0;
3006 * Get / Set Clip Planes
3008 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3010 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3012 /* Validate Index */
3013 if (Index >= GL_LIMITS(clipplanes)) {
3014 TRACE("Application has requested clipplane this device doesn't support\n");
3015 return WINED3DERR_INVALIDCALL;
3018 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3020 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3021 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3022 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3023 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3024 TRACE("Application is setting old values over, nothing to do\n");
3028 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3029 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3030 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3031 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3033 /* Handle recording of state blocks */
3034 if (This->isRecordingState) {
3035 TRACE("Recording... not performing anything\n");
3039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3044 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3045 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3046 TRACE("(%p) : for idx %d\n", This, Index);
3048 /* Validate Index */
3049 if (Index >= GL_LIMITS(clipplanes)) {
3050 TRACE("Application has requested clipplane this device doesn't support\n");
3051 return WINED3DERR_INVALIDCALL;
3054 pPlane[0] = This->stateBlock->clipplane[Index][0];
3055 pPlane[1] = This->stateBlock->clipplane[Index][1];
3056 pPlane[2] = This->stateBlock->clipplane[Index][2];
3057 pPlane[3] = This->stateBlock->clipplane[Index][3];
3062 * Get / Set Clip Plane Status
3063 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3065 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 FIXME("(%p) : stub\n", This);
3068 if (NULL == pClipStatus) {
3069 return WINED3DERR_INVALIDCALL;
3071 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3072 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3076 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3078 FIXME("(%p) : stub\n", This);
3079 if (NULL == pClipStatus) {
3080 return WINED3DERR_INVALIDCALL;
3082 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3083 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3088 * Get / Set Material
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3095 This->updateStateBlock->changed.material = TRUE;
3096 This->updateStateBlock->material = *pMaterial;
3098 /* Handle recording of state blocks */
3099 if (This->isRecordingState) {
3100 TRACE("Recording... not performing anything\n");
3104 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 *pMaterial = This->updateStateBlock->material;
3111 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3112 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3113 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3114 pMaterial->Ambient.b, pMaterial->Ambient.a);
3115 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3116 pMaterial->Specular.b, pMaterial->Specular.a);
3117 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3118 pMaterial->Emissive.b, pMaterial->Emissive.a);
3119 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3127 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3128 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3129 IWineD3DIndexBuffer *oldIdxs;
3131 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3132 oldIdxs = This->updateStateBlock->pIndexData;
3134 This->updateStateBlock->changed.indices = TRUE;
3135 This->updateStateBlock->pIndexData = pIndexData;
3137 /* Handle recording of state blocks */
3138 if (This->isRecordingState) {
3139 TRACE("Recording... not performing anything\n");
3140 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3141 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3145 if(oldIdxs != pIndexData) {
3146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3147 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3148 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3153 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3154 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3156 *ppIndexData = This->stateBlock->pIndexData;
3158 /* up ref count on ppindexdata */
3160 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3161 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3163 TRACE("(%p) No index data set\n", This);
3165 TRACE("Returning %p\n", *ppIndexData);
3170 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3171 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3172 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3173 TRACE("(%p)->(%d)\n", This, BaseIndex);
3175 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3176 TRACE("Application is setting the old value over, nothing to do\n");
3180 This->updateStateBlock->baseVertexIndex = BaseIndex;
3182 if (This->isRecordingState) {
3183 TRACE("Recording... not performing anything\n");
3186 /* The base vertex index affects the stream sources */
3187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3191 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 TRACE("(%p) : base_index %p\n", This, base_index);
3195 *base_index = This->stateBlock->baseVertexIndex;
3197 TRACE("Returning %u\n", *base_index);
3203 * Get / Set Viewports
3205 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 TRACE("(%p)\n", This);
3209 This->updateStateBlock->changed.viewport = TRUE;
3210 This->updateStateBlock->viewport = *pViewport;
3212 /* Handle recording of state blocks */
3213 if (This->isRecordingState) {
3214 TRACE("Recording... not performing anything\n");
3218 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3219 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3226 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p)\n", This);
3229 *pViewport = This->stateBlock->viewport;
3234 * Get / Set Render States
3235 * TODO: Verify against dx9 definitions
3237 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3240 DWORD oldValue = This->stateBlock->renderState[State];
3242 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3244 This->updateStateBlock->changed.renderState[State] = TRUE;
3245 This->updateStateBlock->renderState[State] = Value;
3247 /* Handle recording of state blocks */
3248 if (This->isRecordingState) {
3249 TRACE("Recording... not performing anything\n");
3253 /* Compared here and not before the assignment to allow proper stateblock recording */
3254 if(Value == oldValue) {
3255 TRACE("Application is setting the old value over, nothing to do\n");
3257 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3263 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3265 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3266 *pValue = This->stateBlock->renderState[State];
3271 * Get / Set Sampler States
3272 * TODO: Verify against dx9 definitions
3275 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3276 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3279 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3280 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3282 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3283 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3286 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3287 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3288 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3291 * SetSampler is designed to allow for more than the standard up to 8 textures
3292 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3293 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3295 * http://developer.nvidia.com/object/General_FAQ.html#t6
3297 * There are two new settings for GForce
3299 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3300 * and the texture one:
3301 * GL_MAX_TEXTURE_COORDS_ARB.
3302 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3305 oldValue = This->stateBlock->samplerState[Sampler][Type];
3306 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3307 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3309 /* Handle recording of state blocks */
3310 if (This->isRecordingState) {
3311 TRACE("Recording... not performing anything\n");
3315 if(oldValue == Value) {
3316 TRACE("Application is setting the old value over, nothing to do\n");
3320 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3325 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3328 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3329 This, Sampler, debug_d3dsamplerstate(Type), Type);
3331 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3332 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3335 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3336 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3337 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3339 *Value = This->stateBlock->samplerState[Sampler][Type];
3340 TRACE("(%p) : Returning %#x\n", This, *Value);
3345 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3348 This->updateStateBlock->changed.scissorRect = TRUE;
3349 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3350 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3353 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3355 if(This->isRecordingState) {
3356 TRACE("Recording... not performing anything\n");
3360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3365 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3366 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3368 *pRect = This->updateStateBlock->scissorRect;
3369 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3375 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3377 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3379 This->updateStateBlock->vertexDecl = pDecl;
3380 This->updateStateBlock->changed.vertexDecl = TRUE;
3382 if (This->isRecordingState) {
3383 TRACE("Recording... not performing anything\n");
3385 } else if(pDecl == oldDecl) {
3386 /* Checked after the assignment to allow proper stateblock recording */
3387 TRACE("Application is setting the old declaration over, nothing to do\n");
3391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3395 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3398 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3400 *ppDecl = This->stateBlock->vertexDecl;
3401 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3405 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3406 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3409 This->updateStateBlock->vertexShader = pShader;
3410 This->updateStateBlock->changed.vertexShader = TRUE;
3412 if (This->isRecordingState) {
3413 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3414 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3415 TRACE("Recording... not performing anything\n");
3417 } else if(oldShader == pShader) {
3418 /* Checked here to allow proper stateblock recording */
3419 TRACE("App is setting the old shader over, nothing to do\n");
3423 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3424 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3425 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3427 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3432 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 if (NULL == ppShader) {
3436 return WINED3DERR_INVALIDCALL;
3438 *ppShader = This->stateBlock->vertexShader;
3439 if( NULL != *ppShader)
3440 IWineD3DVertexShader_AddRef(*ppShader);
3442 TRACE("(%p) : returning %p\n", This, *ppShader);
3446 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3447 IWineD3DDevice *iface,
3449 CONST BOOL *srcData,
3452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 int i, cnt = min(count, MAX_CONST_B - start);
3455 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3456 iface, srcData, start, count);
3458 if (srcData == NULL || cnt < 0)
3459 return WINED3DERR_INVALIDCALL;
3461 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3462 for (i = 0; i < cnt; i++)
3463 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3465 for (i = start; i < cnt + start; ++i) {
3466 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3469 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3474 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3475 IWineD3DDevice *iface,
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int cnt = min(count, MAX_CONST_B - start);
3483 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3484 iface, dstData, start, count);
3486 if (dstData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3493 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3494 IWineD3DDevice *iface,
3499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3500 int i, cnt = min(count, MAX_CONST_I - start);
3502 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3503 iface, srcData, start, count);
3505 if (srcData == NULL || cnt < 0)
3506 return WINED3DERR_INVALIDCALL;
3508 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3509 for (i = 0; i < cnt; i++)
3510 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3511 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3513 for (i = start; i < cnt + start; ++i) {
3514 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3517 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3522 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3523 IWineD3DDevice *iface,
3528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3529 int cnt = min(count, MAX_CONST_I - start);
3531 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3532 iface, dstData, start, count);
3534 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3535 return WINED3DERR_INVALIDCALL;
3537 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3541 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3542 IWineD3DDevice *iface,
3544 CONST float *srcData,
3547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3551 iface, srcData, start, count);
3553 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3554 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3555 return WINED3DERR_INVALIDCALL;
3557 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3559 for (i = 0; i < count; i++)
3560 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3561 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3564 for (i = start; i < count + start; ++i) {
3565 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3566 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3567 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3568 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3569 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3571 ptr->idx[ptr->count++] = i;
3572 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3581 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3582 IWineD3DDevice *iface,
3584 CONST float *srcData,
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3590 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3591 iface, srcData, start, count);
3593 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3594 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3595 return WINED3DERR_INVALIDCALL;
3597 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3599 for (i = 0; i < count; i++)
3600 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3601 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3604 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3605 * context. On a context switch the old context will be fully dirtified
3607 memset(This->activeContext->vshader_const_dirty + start, 1,
3608 sizeof(*This->activeContext->vshader_const_dirty) * count);
3609 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3611 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3616 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3617 IWineD3DDevice *iface,
3622 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3623 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3625 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3626 iface, dstData, start, count);
3628 if (dstData == NULL || cnt < 0)
3629 return WINED3DERR_INVALIDCALL;
3631 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3635 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3637 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3642 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3643 int i = This->rev_tex_unit_map[unit];
3644 int j = This->texUnitMap[stage];
3646 This->texUnitMap[stage] = unit;
3647 if (i != -1 && i != stage) {
3648 This->texUnitMap[i] = -1;
3651 This->rev_tex_unit_map[unit] = stage;
3652 if (j != -1 && j != unit) {
3653 This->rev_tex_unit_map[j] = -1;
3657 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3660 for (i = 0; i < MAX_TEXTURES; ++i) {
3661 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3662 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3663 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3664 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3665 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3666 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3667 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3668 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3670 if (color_op == WINED3DTOP_DISABLE) {
3671 /* Not used, and disable higher stages */
3672 while (i < MAX_TEXTURES) {
3673 This->fixed_function_usage_map[i] = FALSE;
3679 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3680 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3681 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3682 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3683 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3684 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3685 This->fixed_function_usage_map[i] = TRUE;
3687 This->fixed_function_usage_map[i] = FALSE;
3690 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3691 This->fixed_function_usage_map[i+1] = TRUE;
3696 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3699 device_update_fixed_function_usage_map(This);
3701 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3702 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3703 if (!This->fixed_function_usage_map[i]) continue;
3705 if (This->texUnitMap[i] != i) {
3706 device_map_stage(This, i, i);
3707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3708 markTextureStagesDirty(This, i);
3714 /* Now work out the mapping */
3716 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3717 if (!This->fixed_function_usage_map[i]) continue;
3719 if (This->texUnitMap[i] != tex) {
3720 device_map_stage(This, i, tex);
3721 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3722 markTextureStagesDirty(This, i);
3729 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3730 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3733 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3734 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3735 device_map_stage(This, i, i);
3736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3737 if (i < MAX_TEXTURES) {
3738 markTextureStagesDirty(This, i);
3744 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3745 int current_mapping = This->rev_tex_unit_map[unit];
3747 if (current_mapping == -1) {
3748 /* Not currently used */
3752 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3753 /* Used by a fragment sampler */
3755 if (!pshader_sampler_tokens) {
3756 /* No pixel shader, check fixed function */
3757 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3760 /* Pixel shader, check the shader's sampler map */
3761 return !pshader_sampler_tokens[current_mapping];
3764 /* Used by a vertex sampler */
3765 return !vshader_sampler_tokens[current_mapping];
3768 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3769 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3770 DWORD *pshader_sampler_tokens = NULL;
3771 int start = GL_LIMITS(combined_samplers) - 1;
3775 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3777 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3778 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3779 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3782 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3783 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3784 if (vshader_sampler_tokens[i]) {
3785 if (This->texUnitMap[vsampler_idx] != -1) {
3786 /* Already mapped somewhere */
3790 while (start >= 0) {
3791 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3792 device_map_stage(This, vsampler_idx, start);
3793 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3805 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3806 BOOL vs = use_vs(This);
3807 BOOL ps = use_ps(This);
3810 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3811 * that would be really messy and require shader recompilation
3812 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3813 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3816 device_map_psamplers(This);
3818 device_map_fixed_function_samplers(This);
3822 device_map_vsamplers(This, ps);
3826 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3828 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3829 This->updateStateBlock->pixelShader = pShader;
3830 This->updateStateBlock->changed.pixelShader = TRUE;
3832 /* Handle recording of state blocks */
3833 if (This->isRecordingState) {
3834 TRACE("Recording... not performing anything\n");
3837 if (This->isRecordingState) {
3838 TRACE("Recording... not performing anything\n");
3839 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3840 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3844 if(pShader == oldShader) {
3845 TRACE("App is setting the old pixel shader over, nothing to do\n");
3849 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3850 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3852 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3858 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3861 if (NULL == ppShader) {
3862 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3863 return WINED3DERR_INVALIDCALL;
3866 *ppShader = This->stateBlock->pixelShader;
3867 if (NULL != *ppShader) {
3868 IWineD3DPixelShader_AddRef(*ppShader);
3870 TRACE("(%p) : returning %p\n", This, *ppShader);
3874 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3875 IWineD3DDevice *iface,
3877 CONST BOOL *srcData,
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 int i, cnt = min(count, MAX_CONST_B - start);
3883 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3884 iface, srcData, start, count);
3886 if (srcData == NULL || cnt < 0)
3887 return WINED3DERR_INVALIDCALL;
3889 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3890 for (i = 0; i < cnt; i++)
3891 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3893 for (i = start; i < cnt + start; ++i) {
3894 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3897 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3902 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3903 IWineD3DDevice *iface,
3908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3909 int cnt = min(count, MAX_CONST_B - start);
3911 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3912 iface, dstData, start, count);
3914 if (dstData == NULL || cnt < 0)
3915 return WINED3DERR_INVALIDCALL;
3917 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3921 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3922 IWineD3DDevice *iface,
3927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3928 int i, cnt = min(count, MAX_CONST_I - start);
3930 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3931 iface, srcData, start, count);
3933 if (srcData == NULL || cnt < 0)
3934 return WINED3DERR_INVALIDCALL;
3936 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3937 for (i = 0; i < cnt; i++)
3938 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3939 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3941 for (i = start; i < cnt + start; ++i) {
3942 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3945 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3950 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3951 IWineD3DDevice *iface,
3956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3957 int cnt = min(count, MAX_CONST_I - start);
3959 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3960 iface, dstData, start, count);
3962 if (dstData == NULL || cnt < 0)
3963 return WINED3DERR_INVALIDCALL;
3965 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3969 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3970 IWineD3DDevice *iface,
3972 CONST float *srcData,
3975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3979 iface, srcData, start, count);
3981 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3982 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3983 return WINED3DERR_INVALIDCALL;
3985 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3987 for (i = 0; i < count; i++)
3988 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3989 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3992 for (i = start; i < count + start; ++i) {
3993 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3994 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3995 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3996 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3997 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3999 ptr->idx[ptr->count++] = i;
4000 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4009 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4010 IWineD3DDevice *iface,
4012 CONST float *srcData,
4015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4018 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4019 iface, srcData, start, count);
4021 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4022 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4023 return WINED3DERR_INVALIDCALL;
4025 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4027 for (i = 0; i < count; i++)
4028 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4029 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4032 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4033 * context. On a context switch the old context will be fully dirtified
4035 memset(This->activeContext->pshader_const_dirty + start, 1,
4036 sizeof(*This->activeContext->pshader_const_dirty) * count);
4037 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4039 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4044 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4045 IWineD3DDevice *iface,
4050 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4051 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4053 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4054 iface, dstData, start, count);
4056 if (dstData == NULL || cnt < 0)
4057 return WINED3DERR_INVALIDCALL;
4059 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4063 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4065 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4066 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4068 DWORD DestFVF = dest->fvf;
4070 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4074 if (lpStrideData->u.s.normal.lpData) {
4075 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4078 if (lpStrideData->u.s.position.lpData == NULL) {
4079 ERR("Source has no position mask\n");
4080 return WINED3DERR_INVALIDCALL;
4083 /* We might access VBOs from this code, so hold the lock */
4086 if (dest->resource.allocatedMemory == NULL) {
4087 /* This may happen if we do direct locking into a vbo. Unlikely,
4088 * but theoretically possible(ddraw processvertices test)
4090 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4091 if(!dest->resource.allocatedMemory) {
4093 ERR("Out of memory\n");
4094 return E_OUTOFMEMORY;
4098 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4099 checkGLcall("glBindBufferARB");
4100 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4102 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4104 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4105 checkGLcall("glUnmapBufferARB");
4109 /* Get a pointer into the destination vbo(create one if none exists) and
4110 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4112 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4113 dest->Flags |= VBFLAG_CREATEVBO;
4114 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4118 unsigned char extrabytes = 0;
4119 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4120 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4121 * this may write 4 extra bytes beyond the area that should be written
4123 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4124 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4125 if(!dest_conv_addr) {
4126 ERR("Out of memory\n");
4127 /* Continue without storing converted vertices */
4129 dest_conv = dest_conv_addr;
4133 * a) WINED3DRS_CLIPPING is enabled
4134 * b) WINED3DVOP_CLIP is passed
4136 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4137 static BOOL warned = FALSE;
4139 * The clipping code is not quite correct. Some things need
4140 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4141 * so disable clipping for now.
4142 * (The graphics in Half-Life are broken, and my processvertices
4143 * test crashes with IDirect3DDevice3)
4149 FIXME("Clipping is broken and disabled for now\n");
4151 } else doClip = FALSE;
4152 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4154 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4157 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4158 WINED3DTS_PROJECTION,
4160 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4161 WINED3DTS_WORLDMATRIX(0),
4164 TRACE("View mat:\n");
4165 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);
4166 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);
4167 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);
4168 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);
4170 TRACE("Proj mat:\n");
4171 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);
4172 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);
4173 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);
4174 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);
4176 TRACE("World mat:\n");
4177 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);
4178 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);
4179 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);
4180 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);
4182 /* Get the viewport */
4183 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4184 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4185 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4187 multiply_matrix(&mat,&view_mat,&world_mat);
4188 multiply_matrix(&mat,&proj_mat,&mat);
4190 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4192 for (i = 0; i < dwCount; i+= 1) {
4193 unsigned int tex_index;
4195 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4196 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4197 /* The position first */
4199 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4201 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4203 /* Multiplication with world, view and projection matrix */
4204 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);
4205 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);
4206 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);
4207 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);
4209 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4211 /* WARNING: The following things are taken from d3d7 and were not yet checked
4212 * against d3d8 or d3d9!
4215 /* Clipping conditions: From msdn
4217 * A vertex is clipped if it does not match the following requirements
4221 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4223 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4224 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4229 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4230 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4233 /* "Normal" viewport transformation (not clipped)
4234 * 1) The values are divided by rhw
4235 * 2) The y axis is negative, so multiply it with -1
4236 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4237 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4238 * 4) Multiply x with Width/2 and add Width/2
4239 * 5) The same for the height
4240 * 6) Add the viewpoint X and Y to the 2D coordinates and
4241 * The minimum Z value to z
4242 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4244 * Well, basically it's simply a linear transformation into viewport
4256 z *= vp.MaxZ - vp.MinZ;
4258 x += vp.Width / 2 + vp.X;
4259 y += vp.Height / 2 + vp.Y;
4264 /* That vertex got clipped
4265 * Contrary to OpenGL it is not dropped completely, it just
4266 * undergoes a different calculation.
4268 TRACE("Vertex got clipped\n");
4275 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4276 * outside of the main vertex buffer memory. That needs some more
4281 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4284 ( (float *) dest_ptr)[0] = x;
4285 ( (float *) dest_ptr)[1] = y;
4286 ( (float *) dest_ptr)[2] = z;
4287 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4289 dest_ptr += 3 * sizeof(float);
4291 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4292 dest_ptr += sizeof(float);
4297 ( (float *) dest_conv)[0] = x * w;
4298 ( (float *) dest_conv)[1] = y * w;
4299 ( (float *) dest_conv)[2] = z * w;
4300 ( (float *) dest_conv)[3] = w;
4302 dest_conv += 3 * sizeof(float);
4304 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4305 dest_conv += sizeof(float);
4309 if (DestFVF & WINED3DFVF_PSIZE) {
4310 dest_ptr += sizeof(DWORD);
4311 if(dest_conv) dest_conv += sizeof(DWORD);
4313 if (DestFVF & WINED3DFVF_NORMAL) {
4315 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4316 /* AFAIK this should go into the lighting information */
4317 FIXME("Didn't expect the destination to have a normal\n");
4318 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4320 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4324 if (DestFVF & WINED3DFVF_DIFFUSE) {
4326 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4328 static BOOL warned = FALSE;
4331 ERR("No diffuse color in source, but destination has one\n");
4335 *( (DWORD *) dest_ptr) = 0xffffffff;
4336 dest_ptr += sizeof(DWORD);
4339 *( (DWORD *) dest_conv) = 0xffffffff;
4340 dest_conv += sizeof(DWORD);
4344 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4346 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4347 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4348 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4349 dest_conv += sizeof(DWORD);
4354 if (DestFVF & WINED3DFVF_SPECULAR) {
4355 /* What's the color value in the feedback buffer? */
4357 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4359 static BOOL warned = FALSE;
4362 ERR("No specular color in source, but destination has one\n");
4366 *( (DWORD *) dest_ptr) = 0xFF000000;
4367 dest_ptr += sizeof(DWORD);
4370 *( (DWORD *) dest_conv) = 0xFF000000;
4371 dest_conv += sizeof(DWORD);
4375 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4377 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4378 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4379 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4380 dest_conv += sizeof(DWORD);
4385 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4387 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4388 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4390 ERR("No source texture, but destination requests one\n");
4391 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4392 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4395 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4397 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4404 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4405 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4406 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4407 dwCount * get_flexible_vertex_size(DestFVF),
4409 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4410 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4417 #undef copy_and_next
4419 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4420 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4421 WineDirect3DVertexStridedData strided;
4422 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4423 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4426 ERR("Output vertex declaration not implemented yet\n");
4429 /* Need any context to write to the vbo. */
4430 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4432 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4433 * control the streamIsUP flag, thus restore it afterwards.
4435 This->stateBlock->streamIsUP = FALSE;
4436 memset(&strided, 0, sizeof(strided));
4437 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4438 This->stateBlock->streamIsUP = streamWasUP;
4440 if(vbo || SrcStartIndex) {
4442 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4443 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4445 * Also get the start index in, but only loop over all elements if there's something to add at all.
4447 #define FIXSRC(type) \
4448 if(strided.u.s.type.VBO) { \
4449 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4450 strided.u.s.type.VBO = 0; \
4451 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4453 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4457 if(strided.u.s.type.lpData) { \
4458 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4461 FIXSRC(blendWeights);
4462 FIXSRC(blendMatrixIndices);
4467 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4468 FIXSRC(texCoords[i]);
4481 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4485 * Get / Set Texture Stage States
4486 * TODO: Verify against dx9 definitions
4488 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4492 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4494 if (Stage >= MAX_TEXTURES) {
4495 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4499 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4500 This->updateStateBlock->textureState[Stage][Type] = Value;
4502 if (This->isRecordingState) {
4503 TRACE("Recording... not performing anything\n");
4507 /* Checked after the assignments to allow proper stateblock recording */
4508 if(oldValue == Value) {
4509 TRACE("App is setting the old value over, nothing to do\n");
4513 if(Stage > This->stateBlock->lowest_disabled_stage &&
4514 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4515 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4516 * Changes in other states are important on disabled stages too
4521 if(Type == WINED3DTSS_COLOROP) {
4524 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4525 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4526 * they have to be disabled
4528 * The current stage is dirtified below.
4530 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4531 TRACE("Additionally dirtifying stage %d\n", i);
4532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4534 This->stateBlock->lowest_disabled_stage = Stage;
4535 TRACE("New lowest disabled: %d\n", Stage);
4536 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4537 /* Previously disabled stage enabled. Stages above it may need enabling
4538 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4539 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4541 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4544 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4545 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4548 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4551 This->stateBlock->lowest_disabled_stage = i;
4552 TRACE("New lowest disabled: %d\n", i);
4554 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4555 /* TODO: Built a stage -> texture unit mapping for register combiners */
4559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4564 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4567 *pValue = This->updateStateBlock->textureState[Stage][Type];
4574 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4576 IWineD3DBaseTexture *oldTexture;
4578 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4580 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4581 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4584 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4585 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4586 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4589 oldTexture = This->updateStateBlock->textures[Stage];
4591 if(pTexture != NULL) {
4592 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4594 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4595 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4596 return WINED3DERR_INVALIDCALL;
4598 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4601 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4602 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4604 This->updateStateBlock->changed.textures[Stage] = TRUE;
4605 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4606 This->updateStateBlock->textures[Stage] = pTexture;
4608 /* Handle recording of state blocks */
4609 if (This->isRecordingState) {
4610 TRACE("Recording... not performing anything\n");
4614 if(oldTexture == pTexture) {
4615 TRACE("App is setting the same texture again, nothing to do\n");
4619 /** NOTE: MSDN says that setTexture increases the reference count,
4620 * and that the application must set the texture back to null (or have a leaky application),
4621 * This means we should pass the refcount up to the parent
4622 *******************************/
4623 if (NULL != This->updateStateBlock->textures[Stage]) {
4624 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4625 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4627 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4628 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4629 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4630 * so the COLOROP and ALPHAOP have to be dirtified.
4632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4635 if(bindCount == 1) {
4636 new->baseTexture.sampler = Stage;
4638 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4642 if (NULL != oldTexture) {
4643 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4644 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4646 IWineD3DBaseTexture_Release(oldTexture);
4647 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4649 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4652 if(bindCount && old->baseTexture.sampler == Stage) {
4654 /* Have to do a search for the other sampler(s) where the texture is bound to
4655 * Shouldn't happen as long as apps bind a texture only to one stage
4657 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4658 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4659 if(This->updateStateBlock->textures[i] == oldTexture) {
4660 old->baseTexture.sampler = i;
4667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4672 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4675 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4677 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4678 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4681 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4682 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4683 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4686 *ppTexture=This->stateBlock->textures[Stage];
4688 IWineD3DBaseTexture_AddRef(*ppTexture);
4690 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4698 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4699 IWineD3DSurface **ppBackBuffer) {
4700 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4701 IWineD3DSwapChain *swapChain;
4704 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4706 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4707 if (hr == WINED3D_OK) {
4708 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4709 IWineD3DSwapChain_Release(swapChain);
4711 *ppBackBuffer = NULL;
4716 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 WARN("(%p) : stub, calling idirect3d for now\n", This);
4719 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4722 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4724 IWineD3DSwapChain *swapChain;
4727 if(iSwapChain > 0) {
4728 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4729 if (hr == WINED3D_OK) {
4730 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4731 IWineD3DSwapChain_Release(swapChain);
4733 FIXME("(%p) Error getting display mode\n", This);
4736 /* Don't read the real display mode,
4737 but return the stored mode instead. X11 can't change the color
4738 depth, and some apps are pretty angry if they SetDisplayMode from
4739 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4741 Also don't relay to the swapchain because with ddraw it's possible
4742 that there isn't a swapchain at all */
4743 pMode->Width = This->ddraw_width;
4744 pMode->Height = This->ddraw_height;
4745 pMode->Format = This->ddraw_format;
4746 pMode->RefreshRate = 0;
4753 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4755 TRACE("(%p)->(%p)\n", This, hWnd);
4757 if(This->ddraw_fullscreen) {
4758 if(This->ddraw_window && This->ddraw_window != hWnd) {
4759 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4761 if(hWnd && This->ddraw_window != hWnd) {
4762 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4766 This->ddraw_window = hWnd;
4770 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4771 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4772 TRACE("(%p)->(%p)\n", This, hWnd);
4774 *hWnd = This->ddraw_window;
4779 * Stateblock related functions
4782 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4783 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4784 IWineD3DStateBlockImpl *object;
4785 HRESULT temp_result;
4788 TRACE("(%p)\n", This);
4790 if (This->isRecordingState) {
4791 return WINED3DERR_INVALIDCALL;
4794 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4795 if (NULL == object ) {
4796 FIXME("(%p)Error allocating memory for stateblock\n", This);
4797 return E_OUTOFMEMORY;
4799 TRACE("(%p) created object %p\n", This, object);
4800 object->wineD3DDevice= This;
4801 /** FIXME: object->parent = parent; **/
4802 object->parent = NULL;
4803 object->blockType = WINED3DSBT_RECORDED;
4805 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4807 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4808 list_init(&object->lightMap[i]);
4811 temp_result = allocate_shader_constants(object);
4812 if (WINED3D_OK != temp_result)
4815 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4816 This->updateStateBlock = object;
4817 This->isRecordingState = TRUE;
4819 TRACE("(%p) recording stateblock %p\n",This , object);
4823 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4824 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4826 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4828 if (!This->isRecordingState) {
4829 FIXME("(%p) not recording! returning error\n", This);
4830 *ppStateBlock = NULL;
4831 return WINED3DERR_INVALIDCALL;
4834 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4835 if(object->changed.renderState[i]) {
4836 object->contained_render_states[object->num_contained_render_states] = i;
4837 object->num_contained_render_states++;
4840 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4841 if(object->changed.transform[i]) {
4842 object->contained_transform_states[object->num_contained_transform_states] = i;
4843 object->num_contained_transform_states++;
4846 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4847 if(object->changed.vertexShaderConstantsF[i]) {
4848 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4849 object->num_contained_vs_consts_f++;
4852 for(i = 0; i < MAX_CONST_I; i++) {
4853 if(object->changed.vertexShaderConstantsI[i]) {
4854 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4855 object->num_contained_vs_consts_i++;
4858 for(i = 0; i < MAX_CONST_B; i++) {
4859 if(object->changed.vertexShaderConstantsB[i]) {
4860 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4861 object->num_contained_vs_consts_b++;
4864 for(i = 0; i < MAX_CONST_I; i++) {
4865 if(object->changed.pixelShaderConstantsI[i]) {
4866 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4867 object->num_contained_ps_consts_i++;
4870 for(i = 0; i < MAX_CONST_B; i++) {
4871 if(object->changed.pixelShaderConstantsB[i]) {
4872 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4873 object->num_contained_ps_consts_b++;
4876 for(i = 0; i < MAX_TEXTURES; i++) {
4877 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4878 if(object->changed.textureState[i][j]) {
4879 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4880 object->contained_tss_states[object->num_contained_tss_states].state = j;
4881 object->num_contained_tss_states++;
4885 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4886 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4887 if(object->changed.samplerState[i][j]) {
4888 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4889 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4890 object->num_contained_sampler_states++;
4895 *ppStateBlock = (IWineD3DStateBlock*) object;
4896 This->isRecordingState = FALSE;
4897 This->updateStateBlock = This->stateBlock;
4898 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4899 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4900 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4905 * Scene related functions
4907 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4908 /* At the moment we have no need for any functionality at the beginning
4910 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4911 TRACE("(%p)\n", This);
4914 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4915 return WINED3DERR_INVALIDCALL;
4917 This->inScene = TRUE;
4921 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4922 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4923 TRACE("(%p)\n", This);
4925 if(!This->inScene) {
4926 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4927 return WINED3DERR_INVALIDCALL;
4930 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4931 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4934 checkGLcall("glFlush");
4937 This->inScene = FALSE;
4941 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4942 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4943 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4945 IWineD3DSwapChain *swapChain = NULL;
4947 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4949 TRACE("(%p) Presenting the frame\n", This);
4951 for(i = 0 ; i < swapchains ; i ++) {
4953 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4954 TRACE("presentinng chain %d, %p\n", i, swapChain);
4955 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4956 IWineD3DSwapChain_Release(swapChain);
4962 /* Not called from the VTable (internal subroutine) */
4963 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4964 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4965 float Z, DWORD Stencil) {
4966 GLbitfield glMask = 0;
4968 WINED3DRECT curRect;
4970 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4971 UINT drawable_width, drawable_height;
4972 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4974 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4975 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4976 * for the cleared parts, and the untouched parts.
4978 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4979 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4980 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4981 * checking all this if the dest surface is in the drawable anyway.
4983 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4985 if(vp->X != 0 || vp->Y != 0 ||
4986 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4987 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4990 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4991 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4992 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4993 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4994 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4997 if(Count > 0 && pRects && (
4998 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4999 pRects[0].x2 < target->currentDesc.Width ||
5000 pRects[0].y2 < target->currentDesc.Height)) {
5001 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5008 target->get_drawable_size(target, &drawable_width, &drawable_height);
5010 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5013 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5014 apply_fbo_state((IWineD3DDevice *) This);
5017 /* Only set the values up once, as they are not changing */
5018 if (Flags & WINED3DCLEAR_STENCIL) {
5019 glClearStencil(Stencil);
5020 checkGLcall("glClearStencil");
5021 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5022 glStencilMask(0xFFFFFFFF);
5025 if (Flags & WINED3DCLEAR_ZBUFFER) {
5026 glDepthMask(GL_TRUE);
5028 checkGLcall("glClearDepth");
5029 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5030 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5032 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5033 if(vp->X != 0 || vp->Y != 0 ||
5034 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5035 depth_copy((IWineD3DDevice *) This);
5037 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5038 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5039 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5040 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5041 depth_copy((IWineD3DDevice *) This);
5043 else if(Count > 0 && pRects && (
5044 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5045 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5046 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5047 depth_copy((IWineD3DDevice *) This);
5050 This->depth_copy_state = WINED3D_DCS_INITIAL;
5053 if (Flags & WINED3DCLEAR_TARGET) {
5054 TRACE("Clearing screen with glClear to color %x\n", Color);
5055 glClearColor(D3DCOLOR_R(Color),
5059 checkGLcall("glClearColor");
5061 /* Clear ALL colors! */
5062 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5063 glMask = glMask | GL_COLOR_BUFFER_BIT;
5066 vp_rect.left = vp->X;
5067 vp_rect.top = vp->Y;
5068 vp_rect.right = vp->X + vp->Width;
5069 vp_rect.bottom = vp->Y + vp->Height;
5070 if (!(Count > 0 && pRects)) {
5071 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5072 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5074 if(This->render_offscreen) {
5075 glScissor(vp_rect.left, vp_rect.top,
5076 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5078 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5079 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5081 checkGLcall("glScissor");
5083 checkGLcall("glClear");
5085 /* Now process each rect in turn */
5086 for (i = 0; i < Count; i++) {
5087 /* Note gl uses lower left, width/height */
5088 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5089 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5090 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5092 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5093 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5094 curRect.x1, (target->currentDesc.Height - curRect.y2),
5095 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5097 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5098 * The rectangle is not cleared, no error is returned, but further rectanlges are
5099 * still cleared if they are valid
5101 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5102 TRACE("Rectangle with negative dimensions, ignoring\n");
5106 if(This->render_offscreen) {
5107 glScissor(curRect.x1, curRect.y1,
5108 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5110 glScissor(curRect.x1, drawable_height - curRect.y2,
5111 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5113 checkGLcall("glScissor");
5116 checkGLcall("glClear");
5120 /* Restore the old values (why..?) */
5121 if (Flags & WINED3DCLEAR_STENCIL) {
5122 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5124 if (Flags & WINED3DCLEAR_TARGET) {
5125 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5126 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5127 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5128 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5129 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5131 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5132 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5134 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5135 /* TODO: Move the fbo logic into ModifyLocation() */
5136 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5137 target->Flags |= SFLAG_INTEXTURE;
5145 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5146 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5147 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5148 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5150 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5151 Count, pRects, Flags, Color, Z, Stencil);
5153 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5154 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5155 /* TODO: What about depth stencil buffers without stencil bits? */
5156 return WINED3DERR_INVALIDCALL;
5159 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5165 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5166 UINT PrimitiveCount) {
5168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5170 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5171 debug_d3dprimitivetype(PrimitiveType),
5172 StartVertex, PrimitiveCount);
5174 if(!This->stateBlock->vertexDecl) {
5175 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5176 return WINED3DERR_INVALIDCALL;
5179 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5180 if(This->stateBlock->streamIsUP) {
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5182 This->stateBlock->streamIsUP = FALSE;
5185 if(This->stateBlock->loadBaseVertexIndex != 0) {
5186 This->stateBlock->loadBaseVertexIndex = 0;
5187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5189 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5190 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5191 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5195 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5196 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5197 WINED3DPRIMITIVETYPE PrimitiveType,
5198 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5202 IWineD3DIndexBuffer *pIB;
5203 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5206 pIB = This->stateBlock->pIndexData;
5208 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5209 * without an index buffer set. (The first time at least...)
5210 * D3D8 simply dies, but I doubt it can do much harm to return
5211 * D3DERR_INVALIDCALL there as well. */
5212 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5213 return WINED3DERR_INVALIDCALL;
5216 if(!This->stateBlock->vertexDecl) {
5217 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5218 return WINED3DERR_INVALIDCALL;
5221 if(This->stateBlock->streamIsUP) {
5222 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5223 This->stateBlock->streamIsUP = FALSE;
5225 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5227 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5228 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5229 minIndex, NumVertices, startIndex, primCount);
5231 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5232 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5238 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5239 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5243 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5244 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5249 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5250 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5251 UINT VertexStreamZeroStride) {
5252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5253 IWineD3DVertexBuffer *vb;
5255 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5256 debug_d3dprimitivetype(PrimitiveType),
5257 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5259 if(!This->stateBlock->vertexDecl) {
5260 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5261 return WINED3DERR_INVALIDCALL;
5264 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5265 vb = This->stateBlock->streamSource[0];
5266 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5267 if(vb) IWineD3DVertexBuffer_Release(vb);
5268 This->stateBlock->streamOffset[0] = 0;
5269 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5270 This->stateBlock->streamIsUP = TRUE;
5271 This->stateBlock->loadBaseVertexIndex = 0;
5273 /* TODO: Only mark dirty if drawing from a different UP address */
5274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5276 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5277 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5279 /* MSDN specifies stream zero settings must be set to NULL */
5280 This->stateBlock->streamStride[0] = 0;
5281 This->stateBlock->streamSource[0] = NULL;
5283 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5284 * the new stream sources or use UP drawing again
5289 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5290 UINT MinVertexIndex, UINT NumVertices,
5291 UINT PrimitiveCount, CONST void* pIndexData,
5292 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5293 UINT VertexStreamZeroStride) {
5295 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5296 IWineD3DVertexBuffer *vb;
5297 IWineD3DIndexBuffer *ib;
5299 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5300 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5301 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5302 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5304 if(!This->stateBlock->vertexDecl) {
5305 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5306 return WINED3DERR_INVALIDCALL;
5309 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5315 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5316 vb = This->stateBlock->streamSource[0];
5317 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5318 if(vb) IWineD3DVertexBuffer_Release(vb);
5319 This->stateBlock->streamIsUP = TRUE;
5320 This->stateBlock->streamOffset[0] = 0;
5321 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5323 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5324 This->stateBlock->baseVertexIndex = 0;
5325 This->stateBlock->loadBaseVertexIndex = 0;
5326 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5327 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5328 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5330 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5332 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5333 This->stateBlock->streamSource[0] = NULL;
5334 This->stateBlock->streamStride[0] = 0;
5335 ib = This->stateBlock->pIndexData;
5337 IWineD3DIndexBuffer_Release(ib);
5338 This->stateBlock->pIndexData = NULL;
5340 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5341 * SetStreamSource to specify a vertex buffer
5347 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5350 /* Mark the state dirty until we have nicer tracking
5351 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5355 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5356 This->stateBlock->baseVertexIndex = 0;
5357 This->up_strided = DrawPrimStrideData;
5358 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5359 This->up_strided = NULL;
5363 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5365 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5367 /* Mark the state dirty until we have nicer tracking
5368 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5373 This->stateBlock->streamIsUP = TRUE;
5374 This->stateBlock->baseVertexIndex = 0;
5375 This->up_strided = DrawPrimStrideData;
5376 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5377 This->up_strided = NULL;
5381 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5382 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5383 * not callable by the app directly no parameter validation checks are needed here.
5385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5386 WINED3DLOCKED_BOX src;
5387 WINED3DLOCKED_BOX dst;
5389 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5391 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5392 * dirtification to improve loading performance.
5394 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5395 if(FAILED(hr)) return hr;
5396 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5398 IWineD3DVolume_UnlockBox(pSourceVolume);
5402 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5404 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5406 IWineD3DVolume_UnlockBox(pSourceVolume);
5408 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5413 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5414 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5416 HRESULT hr = WINED3D_OK;
5417 WINED3DRESOURCETYPE sourceType;
5418 WINED3DRESOURCETYPE destinationType;
5421 /* TODO: think about moving the code into IWineD3DBaseTexture */
5423 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5425 /* verify that the source and destination textures aren't NULL */
5426 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5427 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5428 This, pSourceTexture, pDestinationTexture);
5429 hr = WINED3DERR_INVALIDCALL;
5432 if (pSourceTexture == pDestinationTexture) {
5433 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5434 This, pSourceTexture, pDestinationTexture);
5435 hr = WINED3DERR_INVALIDCALL;
5437 /* Verify that the source and destination textures are the same type */
5438 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5439 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5441 if (sourceType != destinationType) {
5442 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5444 hr = WINED3DERR_INVALIDCALL;
5447 /* check that both textures have the identical numbers of levels */
5448 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5449 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5450 hr = WINED3DERR_INVALIDCALL;
5453 if (WINED3D_OK == hr) {
5455 /* Make sure that the destination texture is loaded */
5456 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5458 /* Update every surface level of the texture */
5459 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5461 switch (sourceType) {
5462 case WINED3DRTYPE_TEXTURE:
5464 IWineD3DSurface *srcSurface;
5465 IWineD3DSurface *destSurface;
5467 for (i = 0 ; i < levels ; ++i) {
5468 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5469 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5470 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5471 IWineD3DSurface_Release(srcSurface);
5472 IWineD3DSurface_Release(destSurface);
5473 if (WINED3D_OK != hr) {
5474 WARN("(%p) : Call to update surface failed\n", This);
5480 case WINED3DRTYPE_CUBETEXTURE:
5482 IWineD3DSurface *srcSurface;
5483 IWineD3DSurface *destSurface;
5484 WINED3DCUBEMAP_FACES faceType;
5486 for (i = 0 ; i < levels ; ++i) {
5487 /* Update each cube face */
5488 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5489 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5490 if (WINED3D_OK != hr) {
5491 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5493 TRACE("Got srcSurface %p\n", srcSurface);
5495 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5496 if (WINED3D_OK != hr) {
5497 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5499 TRACE("Got desrSurface %p\n", destSurface);
5501 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5502 IWineD3DSurface_Release(srcSurface);
5503 IWineD3DSurface_Release(destSurface);
5504 if (WINED3D_OK != hr) {
5505 WARN("(%p) : Call to update surface failed\n", This);
5513 case WINED3DRTYPE_VOLUMETEXTURE:
5515 IWineD3DVolume *srcVolume = NULL;
5516 IWineD3DVolume *destVolume = NULL;
5518 for (i = 0 ; i < levels ; ++i) {
5519 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5520 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5521 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5522 IWineD3DVolume_Release(srcVolume);
5523 IWineD3DVolume_Release(destVolume);
5524 if (WINED3D_OK != hr) {
5525 WARN("(%p) : Call to update volume failed\n", This);
5533 FIXME("(%p) : Unsupported source and destination type\n", This);
5534 hr = WINED3DERR_INVALIDCALL;
5541 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5542 IWineD3DSwapChain *swapChain;
5544 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5545 if(hr == WINED3D_OK) {
5546 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5547 IWineD3DSwapChain_Release(swapChain);
5552 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 /* return a sensible default */
5556 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5557 FIXME("(%p) : stub\n", This);
5561 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5565 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5566 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5567 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5568 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5573 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5577 PALETTEENTRY **palettes;
5579 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5581 if (PaletteNumber >= MAX_PALETTES) {
5582 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5583 return WINED3DERR_INVALIDCALL;
5586 if (PaletteNumber >= This->NumberOfPalettes) {
5587 NewSize = This->NumberOfPalettes;
5590 } while(PaletteNumber >= NewSize);
5591 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5593 ERR("Out of memory!\n");
5594 return E_OUTOFMEMORY;
5596 This->palettes = palettes;
5597 This->NumberOfPalettes = NewSize;
5600 if (!This->palettes[PaletteNumber]) {
5601 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5602 if (!This->palettes[PaletteNumber]) {
5603 ERR("Out of memory!\n");
5604 return E_OUTOFMEMORY;
5608 for (j = 0; j < 256; ++j) {
5609 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5610 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5611 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5612 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5614 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5615 TRACE("(%p) : returning\n", This);
5619 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5622 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5623 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5624 /* What happens in such situation isn't documented; Native seems to silently abort
5625 on such conditions. Return Invalid Call. */
5626 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5627 return WINED3DERR_INVALIDCALL;
5629 for (j = 0; j < 256; ++j) {
5630 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5631 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5632 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5633 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5635 TRACE("(%p) : returning\n", This);
5639 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5640 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5641 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5642 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5643 (tested with reference rasterizer). Return Invalid Call. */
5644 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5645 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5646 return WINED3DERR_INVALIDCALL;
5648 /*TODO: stateblocks */
5649 if (This->currentPalette != PaletteNumber) {
5650 This->currentPalette = PaletteNumber;
5651 dirtify_p8_texture_samplers(This);
5653 TRACE("(%p) : returning\n", This);
5657 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5659 if (PaletteNumber == NULL) {
5660 WARN("(%p) : returning Invalid Call\n", This);
5661 return WINED3DERR_INVALIDCALL;
5663 /*TODO: stateblocks */
5664 *PaletteNumber = This->currentPalette;
5665 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5669 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5670 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5671 static BOOL showFixmes = TRUE;
5673 FIXME("(%p) : stub\n", This);
5677 This->softwareVertexProcessing = bSoftware;
5682 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5684 static BOOL showFixmes = TRUE;
5686 FIXME("(%p) : stub\n", This);
5689 return This->softwareVertexProcessing;
5693 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5695 IWineD3DSwapChain *swapChain;
5698 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5700 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5701 if(hr == WINED3D_OK){
5702 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5703 IWineD3DSwapChain_Release(swapChain);
5705 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5711 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5712 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5713 static BOOL showfixmes = TRUE;
5714 if(nSegments != 0.0f) {
5716 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5723 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5725 static BOOL showfixmes = TRUE;
5727 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5733 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5734 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5735 /** TODO: remove casts to IWineD3DSurfaceImpl
5736 * NOTE: move code to surface to accomplish this
5737 ****************************************/
5738 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5739 int srcWidth, srcHeight;
5740 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5741 WINED3DFORMAT destFormat, srcFormat;
5743 int srcLeft, destLeft, destTop;
5744 WINED3DPOOL srcPool, destPool;
5746 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5747 glDescriptor *glDescription = NULL;
5750 CONVERT_TYPES convert = NO_CONVERSION;
5752 WINED3DSURFACE_DESC winedesc;
5754 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5755 memset(&winedesc, 0, sizeof(winedesc));
5756 winedesc.Width = &srcSurfaceWidth;
5757 winedesc.Height = &srcSurfaceHeight;
5758 winedesc.Pool = &srcPool;
5759 winedesc.Format = &srcFormat;
5761 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5763 winedesc.Width = &destSurfaceWidth;
5764 winedesc.Height = &destSurfaceHeight;
5765 winedesc.Pool = &destPool;
5766 winedesc.Format = &destFormat;
5767 winedesc.Size = &destSize;
5769 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5771 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5772 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5773 return WINED3DERR_INVALIDCALL;
5776 /* This call loads the opengl surface directly, instead of copying the surface to the
5777 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5778 * copy in sysmem and use regular surface loading.
5780 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5781 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5782 if(convert != NO_CONVERSION) {
5783 return IWineD3DSurface_BltFast(pDestinationSurface,
5784 pDestPoint ? pDestPoint->x : 0,
5785 pDestPoint ? pDestPoint->y : 0,
5786 pSourceSurface, (RECT *) pSourceRect, 0);
5789 if (destFormat == WINED3DFMT_UNKNOWN) {
5790 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5791 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5793 /* Get the update surface description */
5794 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5797 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5801 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5802 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5803 checkGLcall("glActiveTextureARB");
5806 /* Make sure the surface is loaded and up to date */
5807 IWineD3DSurface_PreLoad(pDestinationSurface);
5809 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5811 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5812 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5813 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5814 srcLeft = pSourceRect ? pSourceRect->left : 0;
5815 destLeft = pDestPoint ? pDestPoint->x : 0;
5816 destTop = pDestPoint ? pDestPoint->y : 0;
5819 /* This function doesn't support compressed textures
5820 the pitch is just bytesPerPixel * width */
5821 if(srcWidth != srcSurfaceWidth || srcLeft ){
5822 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5823 offset += srcLeft * pSrcSurface->bytesPerPixel;
5824 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5826 /* TODO DXT formats */
5828 if(pSourceRect != NULL && pSourceRect->top != 0){
5829 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5831 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5833 ,glDescription->level
5838 ,glDescription->glFormat
5839 ,glDescription->glType
5840 ,IWineD3DSurface_GetData(pSourceSurface)
5844 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5846 /* need to lock the surface to get the data */
5847 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5850 /* TODO: Cube and volume support */
5852 /* not a whole row so we have to do it a line at a time */
5855 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5856 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5858 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5860 glTexSubImage2D(glDescription->target
5861 ,glDescription->level
5866 ,glDescription->glFormat
5867 ,glDescription->glType
5868 ,data /* could be quicker using */
5873 } else { /* Full width, so just write out the whole texture */
5875 if (WINED3DFMT_DXT1 == destFormat ||
5876 WINED3DFMT_DXT2 == destFormat ||
5877 WINED3DFMT_DXT3 == destFormat ||
5878 WINED3DFMT_DXT4 == destFormat ||
5879 WINED3DFMT_DXT5 == destFormat) {
5880 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5881 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5882 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5883 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5884 } if (destFormat != srcFormat) {
5885 FIXME("Updating mixed format compressed texture is not curretly support\n");
5887 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5888 glDescription->level,
5889 glDescription->glFormatInternal,
5894 IWineD3DSurface_GetData(pSourceSurface));
5897 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5902 glTexSubImage2D(glDescription->target
5903 ,glDescription->level
5908 ,glDescription->glFormat
5909 ,glDescription->glType
5910 ,IWineD3DSurface_GetData(pSourceSurface)
5914 checkGLcall("glTexSubImage2D");
5918 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5919 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5924 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5926 struct WineD3DRectPatch *patch;
5930 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5932 if(!(Handle || pRectPatchInfo)) {
5933 /* TODO: Write a test for the return value, thus the FIXME */
5934 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5935 return WINED3DERR_INVALIDCALL;
5939 i = PATCHMAP_HASHFUNC(Handle);
5941 LIST_FOR_EACH(e, &This->patches[i]) {
5942 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5943 if(patch->Handle == Handle) {
5950 TRACE("Patch does not exist. Creating a new one\n");
5951 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5952 patch->Handle = Handle;
5953 list_add_head(&This->patches[i], &patch->entry);
5955 TRACE("Found existing patch %p\n", patch);
5958 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5959 * attributes we have to tesselate, read back, and draw. This needs a patch
5960 * management structure instance. Create one.
5962 * A possible improvement is to check if a vertex shader is used, and if not directly
5965 FIXME("Drawing an uncached patch. This is slow\n");
5966 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5969 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5970 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5971 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5973 TRACE("Tesselation density or patch info changed, retesselating\n");
5975 if(pRectPatchInfo) {
5976 patch->RectPatchInfo = *pRectPatchInfo;
5978 patch->numSegs[0] = pNumSegs[0];
5979 patch->numSegs[1] = pNumSegs[1];
5980 patch->numSegs[2] = pNumSegs[2];
5981 patch->numSegs[3] = pNumSegs[3];
5983 hr = tesselate_rectpatch(This, patch);
5985 WARN("Patch tesselation failed\n");
5987 /* Do not release the handle to store the params of the patch */
5989 HeapFree(GetProcessHeap(), 0, patch);
5995 This->currentPatch = patch;
5996 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5997 This->currentPatch = NULL;
5999 /* Destroy uncached patches */
6001 HeapFree(GetProcessHeap(), 0, patch->mem);
6002 HeapFree(GetProcessHeap(), 0, patch);
6007 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6009 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6010 FIXME("(%p) : Stub\n", This);
6014 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6017 struct WineD3DRectPatch *patch;
6019 TRACE("(%p) Handle(%d)\n", This, Handle);
6021 i = PATCHMAP_HASHFUNC(Handle);
6022 LIST_FOR_EACH(e, &This->patches[i]) {
6023 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6024 if(patch->Handle == Handle) {
6025 TRACE("Deleting patch %p\n", patch);
6026 list_remove(&patch->entry);
6027 HeapFree(GetProcessHeap(), 0, patch->mem);
6028 HeapFree(GetProcessHeap(), 0, patch);
6033 /* TODO: Write a test for the return value */
6034 FIXME("Attempt to destroy nonexistent patch\n");
6035 return WINED3DERR_INVALIDCALL;
6038 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6040 IWineD3DSwapChain *swapchain;
6042 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6043 if (SUCCEEDED(hr)) {
6044 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6051 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6055 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6056 checkGLcall("glGenFramebuffersEXT()");
6058 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6059 checkGLcall("glBindFramebuffer()");
6062 /* TODO: Handle stencil attachments */
6063 static void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6064 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6066 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6067 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6068 checkGLcall("glFramebufferRenderbufferEXT()");
6070 IWineD3DBaseTextureImpl *texture_impl;
6071 GLenum texttarget, target;
6072 GLint old_binding = 0;
6074 texttarget = depth_stencil_impl->glDescription.target;
6075 if(texttarget == GL_TEXTURE_2D) {
6076 target = GL_TEXTURE_2D;
6077 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6078 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6079 target = GL_TEXTURE_RECTANGLE_ARB;
6080 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6082 target = GL_TEXTURE_CUBE_MAP_ARB;
6083 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6086 IWineD3DSurface_PreLoad(depth_stencil);
6088 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6089 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6090 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6091 glBindTexture(target, old_binding);
6093 /* Update base texture states array */
6094 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6095 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6096 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6097 if (texture_impl->baseTexture.bindCount) {
6098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6101 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6104 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6105 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6106 checkGLcall("glFramebufferTexture2DEXT()");
6110 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6111 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6112 IWineD3DBaseTextureImpl *texture_impl;
6113 GLenum texttarget, target;
6116 texttarget = surface_impl->glDescription.target;
6117 if(texttarget == GL_TEXTURE_2D) {
6118 target = GL_TEXTURE_2D;
6119 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6120 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6121 target = GL_TEXTURE_RECTANGLE_ARB;
6122 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6124 target = GL_TEXTURE_CUBE_MAP_ARB;
6125 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6128 IWineD3DSurface_PreLoad(surface);
6130 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6131 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6132 glBindTexture(target, old_binding);
6134 /* Update base texture states array */
6135 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6136 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6137 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6138 if (texture_impl->baseTexture.bindCount) {
6139 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6142 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6145 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6146 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6148 checkGLcall("attach_surface_fbo");
6151 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6153 IWineD3DSwapChain *swapchain;
6155 swapchain = get_swapchain(surface);
6159 TRACE("Surface %p is onscreen\n", surface);
6161 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6162 buffer = surface_get_gl_buffer(surface, swapchain);
6163 glDrawBuffer(buffer);
6164 checkGLcall("glDrawBuffer()");
6166 TRACE("Surface %p is offscreen\n", surface);
6167 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6168 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6172 glEnable(GL_SCISSOR_TEST);
6174 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6176 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6177 rect->x2 - rect->x1, rect->y2 - rect->y1);
6179 checkGLcall("glScissor");
6181 glDisable(GL_SCISSOR_TEST);
6183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6185 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6188 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6189 glClear(GL_COLOR_BUFFER_BIT);
6190 checkGLcall("glClear");
6192 if (This->render_offscreen) {
6193 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6195 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6196 checkGLcall("glBindFramebuffer()");
6199 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6200 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6201 glDrawBuffer(GL_BACK);
6202 checkGLcall("glDrawBuffer()");
6206 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6207 unsigned int r, g, b, a;
6210 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6211 destfmt == WINED3DFMT_R8G8B8)
6214 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6216 a = (color & 0xff000000) >> 24;
6217 r = (color & 0x00ff0000) >> 16;
6218 g = (color & 0x0000ff00) >> 8;
6219 b = (color & 0x000000ff) >> 0;
6223 case WINED3DFMT_R5G6B5:
6224 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6231 TRACE("Returning %08x\n", ret);
6234 case WINED3DFMT_X1R5G5B5:
6235 case WINED3DFMT_A1R5G5B5:
6244 TRACE("Returning %08x\n", ret);
6248 TRACE("Returning %08x\n", a);
6251 case WINED3DFMT_X4R4G4B4:
6252 case WINED3DFMT_A4R4G4B4:
6261 TRACE("Returning %08x\n", ret);
6264 case WINED3DFMT_R3G3B2:
6271 TRACE("Returning %08x\n", ret);
6274 case WINED3DFMT_X8B8G8R8:
6275 case WINED3DFMT_A8B8G8R8:
6280 TRACE("Returning %08x\n", ret);
6283 case WINED3DFMT_A2R10G10B10:
6285 r = (r * 1024) / 256;
6286 g = (g * 1024) / 256;
6287 b = (b * 1024) / 256;
6292 TRACE("Returning %08x\n", ret);
6295 case WINED3DFMT_A2B10G10R10:
6297 r = (r * 1024) / 256;
6298 g = (g * 1024) / 256;
6299 b = (b * 1024) / 256;
6304 TRACE("Returning %08x\n", ret);
6308 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6313 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6315 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6317 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6319 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6320 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6321 return WINED3DERR_INVALIDCALL;
6324 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6326 color_fill_fbo(iface, pSurface, pRect, color);
6330 /* Just forward this to the DirectDraw blitting engine */
6331 memset(&BltFx, 0, sizeof(BltFx));
6332 BltFx.dwSize = sizeof(BltFx);
6333 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6334 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6338 /* rendertarget and depth stencil functions */
6339 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6342 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6343 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6344 return WINED3DERR_INVALIDCALL;
6347 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6348 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6349 /* Note inc ref on returned surface */
6350 if(*ppRenderTarget != NULL)
6351 IWineD3DSurface_AddRef(*ppRenderTarget);
6355 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6357 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6358 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6359 IWineD3DSwapChainImpl *Swapchain;
6362 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6364 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6365 if(hr != WINED3D_OK) {
6366 ERR("Can't get the swapchain\n");
6370 /* Make sure to release the swapchain */
6371 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6373 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6374 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6375 return WINED3DERR_INVALIDCALL;
6377 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6378 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6379 return WINED3DERR_INVALIDCALL;
6382 if(Swapchain->frontBuffer != Front) {
6383 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6385 if(Swapchain->frontBuffer)
6386 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6387 Swapchain->frontBuffer = Front;
6389 if(Swapchain->frontBuffer) {
6390 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6394 if(Back && !Swapchain->backBuffer) {
6395 /* We need memory for the back buffer array - only one back buffer this way */
6396 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6397 if(!Swapchain->backBuffer) {
6398 ERR("Out of memory\n");
6399 return E_OUTOFMEMORY;
6403 if(Swapchain->backBuffer[0] != Back) {
6404 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6406 /* What to do about the context here in the case of multithreading? Not sure.
6407 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6410 if(!Swapchain->backBuffer[0]) {
6411 /* GL was told to draw to the front buffer at creation,
6414 glDrawBuffer(GL_BACK);
6415 checkGLcall("glDrawBuffer(GL_BACK)");
6416 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6417 Swapchain->presentParms.BackBufferCount = 1;
6419 /* That makes problems - disable for now */
6420 /* glDrawBuffer(GL_FRONT); */
6421 checkGLcall("glDrawBuffer(GL_FRONT)");
6422 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6423 Swapchain->presentParms.BackBufferCount = 0;
6427 if(Swapchain->backBuffer[0])
6428 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6429 Swapchain->backBuffer[0] = Back;
6431 if(Swapchain->backBuffer[0]) {
6432 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6434 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6435 Swapchain->backBuffer = NULL;
6443 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6445 *ppZStencilSurface = This->stencilBufferTarget;
6446 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6448 if(*ppZStencilSurface != NULL) {
6449 /* Note inc ref on returned surface */
6450 IWineD3DSurface_AddRef(*ppZStencilSurface);
6453 return WINED3DERR_NOTFOUND;
6457 /* TODO: Handle stencil attachments */
6458 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6461 TRACE("Set depth stencil to %p\n", depth_stencil);
6463 if (depth_stencil) {
6464 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6466 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6467 checkGLcall("glFramebufferTexture2DEXT()");
6471 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6474 TRACE("Set render target %u to %p\n", idx, render_target);
6476 if (render_target) {
6477 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6478 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6480 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6481 checkGLcall("glFramebufferTexture2DEXT()");
6483 This->draw_buffers[idx] = GL_NONE;
6487 static void check_fbo_status(IWineD3DDevice *iface) {
6488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6491 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6492 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6493 TRACE("FBO complete\n");
6495 IWineD3DSurfaceImpl *attachment;
6497 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6499 /* Dump the FBO attachments */
6500 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6501 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6503 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6504 attachment->pow2Width, attachment->pow2Height);
6507 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6509 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6510 attachment->pow2Width, attachment->pow2Height);
6515 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6517 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6518 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6520 if (!ds_impl) return FALSE;
6522 if (ds_impl->current_renderbuffer) {
6523 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6524 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6527 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6528 rt_impl->pow2Height != ds_impl->pow2Height);
6531 void apply_fbo_state(IWineD3DDevice *iface) {
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6535 if (This->render_offscreen) {
6536 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6538 /* Apply render targets */
6539 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6540 IWineD3DSurface *render_target = This->render_targets[i];
6541 if (This->fbo_color_attachments[i] != render_target) {
6542 set_render_target_fbo(iface, i, render_target);
6543 This->fbo_color_attachments[i] = render_target;
6547 /* Apply depth targets */
6548 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6549 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6550 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6552 if (This->stencilBufferTarget) {
6553 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6555 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6556 This->fbo_depth_attachment = This->stencilBufferTarget;
6559 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6560 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6561 checkGLcall("glDrawBuffers()");
6563 glDrawBuffer(This->draw_buffers[0]);
6564 checkGLcall("glDrawBuffer()");
6567 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6570 check_fbo_status(iface);
6573 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6574 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6576 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6577 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6580 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6581 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6582 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6583 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6586 case WINED3DTEXF_LINEAR:
6587 gl_filter = GL_LINEAR;
6591 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6592 case WINED3DTEXF_NONE:
6593 case WINED3DTEXF_POINT:
6594 gl_filter = GL_NEAREST;
6598 /* Attach src surface to src fbo */
6599 src_swapchain = get_swapchain(src_surface);
6600 if (src_swapchain) {
6603 TRACE("Source surface %p is onscreen\n", src_surface);
6604 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6605 /* Make sure the drawable is up to date. In the offscreen case
6606 * attach_surface_fbo() implicitly takes care of this. */
6607 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6610 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6611 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6612 glReadBuffer(buffer);
6613 checkGLcall("glReadBuffer()");
6615 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6616 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6618 TRACE("Source surface %p is offscreen\n", src_surface);
6620 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6621 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6622 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6623 checkGLcall("glReadBuffer()");
6627 /* Attach dst surface to dst fbo */
6628 dst_swapchain = get_swapchain(dst_surface);
6629 if (dst_swapchain) {
6632 TRACE("Destination surface %p is onscreen\n", dst_surface);
6633 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6634 /* Make sure the drawable is up to date. In the offscreen case
6635 * attach_surface_fbo() implicitly takes care of this. */
6636 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6639 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6640 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6641 glDrawBuffer(buffer);
6642 checkGLcall("glDrawBuffer()");
6644 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6645 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6647 TRACE("Destination surface %p is offscreen\n", dst_surface);
6649 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6650 if(!src_swapchain) {
6651 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6655 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6656 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6657 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6658 checkGLcall("glDrawBuffer()");
6660 glDisable(GL_SCISSOR_TEST);
6661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6664 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6665 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6666 checkGLcall("glBlitFramebuffer()");
6668 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6669 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6670 checkGLcall("glBlitFramebuffer()");
6673 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6675 if (This->render_offscreen) {
6676 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6678 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6679 checkGLcall("glBindFramebuffer()");
6682 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6683 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6684 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6685 glDrawBuffer(GL_BACK);
6686 checkGLcall("glDrawBuffer()");
6691 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6693 WINED3DVIEWPORT viewport;
6695 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6697 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6698 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6699 This, RenderTargetIndex, GL_LIMITS(buffers));
6700 return WINED3DERR_INVALIDCALL;
6703 /* MSDN says that null disables the render target
6704 but a device must always be associated with a render target
6705 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6707 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6708 FIXME("Trying to set render target 0 to NULL\n");
6709 return WINED3DERR_INVALIDCALL;
6711 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6712 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);
6713 return WINED3DERR_INVALIDCALL;
6716 /* If we are trying to set what we already have, don't bother */
6717 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6718 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6721 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6722 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6723 This->render_targets[RenderTargetIndex] = pRenderTarget;
6725 /* Render target 0 is special */
6726 if(RenderTargetIndex == 0) {
6727 /* Finally, reset the viewport as the MSDN states. */
6728 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6729 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6732 viewport.MaxZ = 1.0f;
6733 viewport.MinZ = 0.0f;
6734 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6735 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6736 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6740 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6742 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6743 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6745 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6750 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6752 HRESULT hr = WINED3D_OK;
6753 IWineD3DSurface *tmp;
6755 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6757 if (pNewZStencil == This->stencilBufferTarget) {
6758 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6760 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6761 * depending on the renter target implementation being used.
6762 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6763 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6764 * stencil buffer and incur an extra memory overhead
6765 ******************************************************/
6767 tmp = This->stencilBufferTarget;
6768 This->stencilBufferTarget = pNewZStencil;
6769 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6770 /* should we be calling the parent or the wined3d surface? */
6771 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6772 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6775 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6776 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6778 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6779 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6786 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6787 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6789 /* TODO: the use of Impl is deprecated. */
6790 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6791 WINED3DLOCKED_RECT lockedRect;
6793 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6795 /* some basic validation checks */
6796 if(This->cursorTexture) {
6797 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6799 glDeleteTextures(1, &This->cursorTexture);
6801 This->cursorTexture = 0;
6804 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6805 This->haveHardwareCursor = TRUE;
6807 This->haveHardwareCursor = FALSE;
6810 WINED3DLOCKED_RECT rect;
6812 /* MSDN: Cursor must be A8R8G8B8 */
6813 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6814 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6815 return WINED3DERR_INVALIDCALL;
6818 /* MSDN: Cursor must be smaller than the display mode */
6819 if(pSur->currentDesc.Width > This->ddraw_width ||
6820 pSur->currentDesc.Height > This->ddraw_height) {
6821 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);
6822 return WINED3DERR_INVALIDCALL;
6825 if (!This->haveHardwareCursor) {
6826 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6828 /* Do not store the surface's pointer because the application may
6829 * release it after setting the cursor image. Windows doesn't
6830 * addref the set surface, so we can't do this either without
6831 * creating circular refcount dependencies. Copy out the gl texture
6834 This->cursorWidth = pSur->currentDesc.Width;
6835 This->cursorHeight = pSur->currentDesc.Height;
6836 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6838 const GlPixelFormatDesc *glDesc;
6839 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6840 char *mem, *bits = (char *)rect.pBits;
6841 GLint intfmt = glDesc->glInternal;
6842 GLint format = glDesc->glFormat;
6843 GLint type = glDesc->glType;
6844 INT height = This->cursorHeight;
6845 INT width = This->cursorWidth;
6846 INT bpp = tableEntry->bpp;
6849 /* Reformat the texture memory (pitch and width can be
6851 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6852 for(i = 0; i < height; i++)
6853 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6854 IWineD3DSurface_UnlockRect(pCursorBitmap);
6857 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6858 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6859 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6862 /* Make sure that a proper texture unit is selected */
6863 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6864 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6865 checkGLcall("glActiveTextureARB");
6867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6868 /* Create a new cursor texture */
6869 glGenTextures(1, &This->cursorTexture);
6870 checkGLcall("glGenTextures");
6871 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6872 checkGLcall("glBindTexture");
6873 /* Copy the bitmap memory into the cursor texture */
6874 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6875 HeapFree(GetProcessHeap(), 0, mem);
6876 checkGLcall("glTexImage2D");
6878 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6879 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6880 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6887 FIXME("A cursor texture was not returned.\n");
6888 This->cursorTexture = 0;
6893 /* Draw a hardware cursor */
6894 ICONINFO cursorInfo;
6896 /* Create and clear maskBits because it is not needed for
6897 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6899 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6900 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6901 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6902 WINED3DLOCK_NO_DIRTY_UPDATE |
6903 WINED3DLOCK_READONLY
6905 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6906 pSur->currentDesc.Height);
6908 cursorInfo.fIcon = FALSE;
6909 cursorInfo.xHotspot = XHotSpot;
6910 cursorInfo.yHotspot = YHotSpot;
6911 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6912 pSur->currentDesc.Height, 1,
6914 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6915 pSur->currentDesc.Height, 1,
6916 32, lockedRect.pBits);
6917 IWineD3DSurface_UnlockRect(pCursorBitmap);
6918 /* Create our cursor and clean up. */
6919 cursor = CreateIconIndirect(&cursorInfo);
6921 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6922 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6923 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6924 This->hardwareCursor = cursor;
6925 HeapFree(GetProcessHeap(), 0, maskBits);
6929 This->xHotSpot = XHotSpot;
6930 This->yHotSpot = YHotSpot;
6934 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6936 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6938 This->xScreenSpace = XScreenSpace;
6939 This->yScreenSpace = YScreenSpace;
6945 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6947 BOOL oldVisible = This->bCursorVisible;
6950 TRACE("(%p) : visible(%d)\n", This, bShow);
6953 * When ShowCursor is first called it should make the cursor appear at the OS's last
6954 * known cursor position. Because of this, some applications just repetitively call
6955 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6958 This->xScreenSpace = pt.x;
6959 This->yScreenSpace = pt.y;
6961 if (This->haveHardwareCursor) {
6962 This->bCursorVisible = bShow;
6964 SetCursor(This->hardwareCursor);
6970 if (This->cursorTexture)
6971 This->bCursorVisible = bShow;
6977 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6978 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6979 IWineD3DResourceImpl *resource;
6980 TRACE("(%p) : state (%u)\n", This, This->state);
6982 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6983 switch (This->state) {
6986 case WINED3DERR_DEVICELOST:
6988 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6989 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6990 return WINED3DERR_DEVICENOTRESET;
6992 return WINED3DERR_DEVICELOST;
6994 case WINED3DERR_DRIVERINTERNALERROR:
6995 return WINED3DERR_DRIVERINTERNALERROR;
6999 return WINED3DERR_DRIVERINTERNALERROR;
7003 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7004 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7005 /** FIXME: Resource tracking needs to be done,
7006 * The closes we can do to this is set the priorities of all managed textures low
7007 * and then reset them.
7008 ***********************************************************/
7009 FIXME("(%p) : stub\n", This);
7013 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7014 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7016 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7017 if(surface->Flags & SFLAG_DIBSECTION) {
7018 /* Release the DC */
7019 SelectObject(surface->hDC, surface->dib.holdbitmap);
7020 DeleteDC(surface->hDC);
7021 /* Release the DIB section */
7022 DeleteObject(surface->dib.DIBsection);
7023 surface->dib.bitmap_data = NULL;
7024 surface->resource.allocatedMemory = NULL;
7025 surface->Flags &= ~SFLAG_DIBSECTION;
7027 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7028 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7029 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7030 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7031 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7033 surface->pow2Width = surface->pow2Height = 1;
7034 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7035 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7037 surface->glRect.left = 0;
7038 surface->glRect.top = 0;
7039 surface->glRect.right = surface->pow2Width;
7040 surface->glRect.bottom = surface->pow2Height;
7042 if(surface->glDescription.textureName) {
7043 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7045 glDeleteTextures(1, &surface->glDescription.textureName);
7047 surface->glDescription.textureName = 0;
7048 surface->Flags &= ~SFLAG_CLIENT;
7050 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7051 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7052 surface->Flags |= SFLAG_NONPOW2;
7054 surface->Flags &= ~SFLAG_NONPOW2;
7056 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7057 surface->resource.allocatedMemory = NULL;
7058 surface->resource.heapMemory = NULL;
7059 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7060 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7061 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7062 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7064 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7068 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7069 TRACE("Unloading resource %p\n", resource);
7070 IWineD3DResource_UnLoad(resource);
7071 IWineD3DResource_Release(resource);
7075 static void reset_fbo_state(IWineD3DDevice *iface) {
7076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7080 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7081 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7084 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7087 if (This->src_fbo) {
7088 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7091 if (This->dst_fbo) {
7092 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7095 checkGLcall("Tear down FBOs\n");
7098 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7099 This->fbo_color_attachments[i] = NULL;
7101 This->fbo_depth_attachment = NULL;
7104 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7106 WINED3DDISPLAYMODE m;
7109 /* All Windowed modes are supported, as is leaving the current mode */
7110 if(pp->Windowed) return TRUE;
7111 if(!pp->BackBufferWidth) return TRUE;
7112 if(!pp->BackBufferHeight) return TRUE;
7114 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7115 for(i = 0; i < count; i++) {
7116 memset(&m, 0, sizeof(m));
7117 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7119 ERR("EnumAdapterModes failed\n");
7121 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7122 /* Mode found, it is supported */
7126 /* Mode not found -> not supported */
7130 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7132 IWineD3DSwapChainImpl *swapchain;
7134 BOOL DisplayModeChanged = FALSE;
7135 WINED3DDISPLAYMODE mode;
7136 IWineD3DBaseShaderImpl *shader;
7137 IWineD3DSurfaceImpl *target;
7139 TRACE("(%p)\n", This);
7141 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7143 ERR("Failed to get the first implicit swapchain\n");
7147 if(!is_display_mode_supported(This, pPresentationParameters)) {
7148 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7149 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7150 pPresentationParameters->BackBufferHeight);
7151 return WINED3DERR_INVALIDCALL;
7154 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7155 * on an existing gl context, so there's no real need for recreation.
7157 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7159 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7161 TRACE("New params:\n");
7162 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7163 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7164 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7165 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7166 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7167 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7168 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7169 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7170 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7171 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7172 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7173 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7174 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7176 /* No special treatment of these parameters. Just store them */
7177 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7178 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7179 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7180 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7182 /* What to do about these? */
7183 if(pPresentationParameters->BackBufferCount != 0 &&
7184 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7185 ERR("Cannot change the back buffer count yet\n");
7187 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7188 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7189 ERR("Cannot change the back buffer format yet\n");
7191 if(pPresentationParameters->hDeviceWindow != NULL &&
7192 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7193 ERR("Cannot change the device window yet\n");
7195 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7196 ERR("What do do about a changed auto depth stencil parameter?\n");
7199 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7200 reset_fbo_state((IWineD3DDevice *) This);
7203 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7204 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7205 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7209 if(This->depth_blt_texture) {
7210 glDeleteTextures(1, &This->depth_blt_texture);
7211 This->depth_blt_texture = 0;
7213 This->shader_backend->shader_destroy_depth_blt(iface);
7214 This->shader_backend->shader_free_private(iface);
7216 for (i = 0; i < GL_LIMITS(textures); i++) {
7217 /* Textures are recreated below */
7218 glDeleteTextures(1, &This->dummyTextureName[i]);
7219 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7220 This->dummyTextureName[i] = 0;
7224 while(This->numContexts) {
7225 DestroyContext(This, This->contexts[0]);
7227 This->activeContext = NULL;
7228 HeapFree(GetProcessHeap(), 0, swapchain->context);
7229 swapchain->context = NULL;
7230 swapchain->num_contexts = 0;
7232 if(pPresentationParameters->Windowed) {
7233 mode.Width = swapchain->orig_width;
7234 mode.Height = swapchain->orig_height;
7235 mode.RefreshRate = 0;
7236 mode.Format = swapchain->presentParms.BackBufferFormat;
7238 mode.Width = pPresentationParameters->BackBufferWidth;
7239 mode.Height = pPresentationParameters->BackBufferHeight;
7240 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7241 mode.Format = swapchain->presentParms.BackBufferFormat;
7244 /* Should Width == 800 && Height == 0 set 800x600? */
7245 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7246 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7247 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7254 vp.Width = pPresentationParameters->BackBufferWidth;
7255 vp.Height = pPresentationParameters->BackBufferHeight;
7259 if(!pPresentationParameters->Windowed) {
7260 DisplayModeChanged = TRUE;
7262 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7263 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7265 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7266 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7267 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7269 if(This->auto_depth_stencil_buffer) {
7270 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7274 /* Now set the new viewport */
7275 IWineD3DDevice_SetViewport(iface, &vp);
7278 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7279 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7280 DisplayModeChanged) {
7282 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7283 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7284 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7285 } else if(!pPresentationParameters->Windowed) {
7286 DWORD style = This->style, exStyle = This->exStyle;
7287 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7288 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7289 * Reset to clear up their mess. Guild Wars also loses the device during that.
7293 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7294 This->style = style;
7295 This->exStyle = exStyle;
7298 /* Recreate the primary swapchain's context */
7299 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7300 if(swapchain->backBuffer) {
7301 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7303 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7305 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7306 &swapchain->presentParms);
7307 swapchain->num_contexts = 1;
7308 This->activeContext = swapchain->context[0];
7309 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7311 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7313 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7315 create_dummy_textures(This);
7318 hr = This->shader_backend->shader_alloc_private(iface);
7320 ERR("Failed to recreate shader private data\n");
7324 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7330 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7332 /** FIXME: always true at the moment **/
7333 if(!bEnableDialogs) {
7334 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7340 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7342 TRACE("(%p) : pParameters %p\n", This, pParameters);
7344 *pParameters = This->createParms;
7348 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7349 IWineD3DSwapChain *swapchain;
7351 TRACE("Relaying to swapchain\n");
7353 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7354 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7355 IWineD3DSwapChain_Release(swapchain);
7360 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7361 IWineD3DSwapChain *swapchain;
7363 TRACE("Relaying to swapchain\n");
7365 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7366 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7367 IWineD3DSwapChain_Release(swapchain);
7373 /** ********************************************************
7374 * Notification functions
7375 ** ********************************************************/
7376 /** This function must be called in the release of a resource when ref == 0,
7377 * the contents of resource must still be correct,
7378 * any handles to other resource held by the caller must be closed
7379 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7380 *****************************************************/
7381 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7384 TRACE("(%p) : Adding Resource %p\n", This, resource);
7385 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7388 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7391 TRACE("(%p) : Removing resource %p\n", This, resource);
7393 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7397 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7401 TRACE("(%p) : resource %p\n", This, resource);
7402 switch(IWineD3DResource_GetType(resource)){
7403 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7404 case WINED3DRTYPE_SURFACE: {
7407 /* Cleanup any FBO attachments if d3d is enabled */
7408 if(This->d3d_initialized) {
7409 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7410 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7412 TRACE("Last active render target destroyed\n");
7413 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7414 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7415 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7416 * and the lastActiveRenderTarget member shouldn't matter
7419 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7420 TRACE("Activating primary back buffer\n");
7421 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7422 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7423 /* Single buffering environment */
7424 TRACE("Activating primary front buffer\n");
7425 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7427 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7428 /* Implicit render target destroyed, that means the device is being destroyed
7429 * whatever we set here, it shouldn't matter
7431 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7434 /* May happen during ddraw uninitialization */
7435 TRACE("Render target set, but swapchain does not exist!\n");
7436 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7441 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7442 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7443 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7444 set_render_target_fbo(iface, i, NULL);
7445 This->fbo_color_attachments[i] = NULL;
7448 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7449 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7450 set_depth_stencil_fbo(iface, NULL);
7451 This->fbo_depth_attachment = NULL;
7458 case WINED3DRTYPE_TEXTURE:
7459 case WINED3DRTYPE_CUBETEXTURE:
7460 case WINED3DRTYPE_VOLUMETEXTURE:
7461 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7462 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7463 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7464 This->stateBlock->textures[counter] = NULL;
7466 if (This->updateStateBlock != This->stateBlock ){
7467 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7468 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7469 This->updateStateBlock->textures[counter] = NULL;
7474 case WINED3DRTYPE_VOLUME:
7475 /* TODO: nothing really? */
7477 case WINED3DRTYPE_VERTEXBUFFER:
7478 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7481 TRACE("Cleaning up stream pointers\n");
7483 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7484 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7485 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7487 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7488 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7489 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7490 This->updateStateBlock->streamSource[streamNumber] = 0;
7491 /* Set changed flag? */
7494 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) */
7495 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7496 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7497 This->stateBlock->streamSource[streamNumber] = 0;
7500 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7501 else { /* This shouldn't happen */
7502 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7509 case WINED3DRTYPE_INDEXBUFFER:
7510 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7511 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7512 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7513 This->updateStateBlock->pIndexData = NULL;
7516 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7517 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7518 This->stateBlock->pIndexData = NULL;
7524 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7529 /* Remove the resource from the resourceStore */
7530 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7532 TRACE("Resource released\n");
7536 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7538 IWineD3DResourceImpl *resource, *cursor;
7540 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7542 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7543 TRACE("enumerating resource %p\n", resource);
7544 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7545 ret = pCallback((IWineD3DResource *) resource, pData);
7546 if(ret == S_FALSE) {
7547 TRACE("Canceling enumeration\n");
7554 /**********************************************************
7555 * IWineD3DDevice VTbl follows
7556 **********************************************************/
7558 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7560 /*** IUnknown methods ***/
7561 IWineD3DDeviceImpl_QueryInterface,
7562 IWineD3DDeviceImpl_AddRef,
7563 IWineD3DDeviceImpl_Release,
7564 /*** IWineD3DDevice methods ***/
7565 IWineD3DDeviceImpl_GetParent,
7566 /*** Creation methods**/
7567 IWineD3DDeviceImpl_CreateVertexBuffer,
7568 IWineD3DDeviceImpl_CreateIndexBuffer,
7569 IWineD3DDeviceImpl_CreateStateBlock,
7570 IWineD3DDeviceImpl_CreateSurface,
7571 IWineD3DDeviceImpl_CreateTexture,
7572 IWineD3DDeviceImpl_CreateVolumeTexture,
7573 IWineD3DDeviceImpl_CreateVolume,
7574 IWineD3DDeviceImpl_CreateCubeTexture,
7575 IWineD3DDeviceImpl_CreateQuery,
7576 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7577 IWineD3DDeviceImpl_CreateVertexDeclaration,
7578 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7579 IWineD3DDeviceImpl_CreateVertexShader,
7580 IWineD3DDeviceImpl_CreatePixelShader,
7581 IWineD3DDeviceImpl_CreatePalette,
7582 /*** Odd functions **/
7583 IWineD3DDeviceImpl_Init3D,
7584 IWineD3DDeviceImpl_Uninit3D,
7585 IWineD3DDeviceImpl_SetFullscreen,
7586 IWineD3DDeviceImpl_SetMultithreaded,
7587 IWineD3DDeviceImpl_EvictManagedResources,
7588 IWineD3DDeviceImpl_GetAvailableTextureMem,
7589 IWineD3DDeviceImpl_GetBackBuffer,
7590 IWineD3DDeviceImpl_GetCreationParameters,
7591 IWineD3DDeviceImpl_GetDeviceCaps,
7592 IWineD3DDeviceImpl_GetDirect3D,
7593 IWineD3DDeviceImpl_GetDisplayMode,
7594 IWineD3DDeviceImpl_SetDisplayMode,
7595 IWineD3DDeviceImpl_GetHWND,
7596 IWineD3DDeviceImpl_SetHWND,
7597 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7598 IWineD3DDeviceImpl_GetRasterStatus,
7599 IWineD3DDeviceImpl_GetSwapChain,
7600 IWineD3DDeviceImpl_Reset,
7601 IWineD3DDeviceImpl_SetDialogBoxMode,
7602 IWineD3DDeviceImpl_SetCursorProperties,
7603 IWineD3DDeviceImpl_SetCursorPosition,
7604 IWineD3DDeviceImpl_ShowCursor,
7605 IWineD3DDeviceImpl_TestCooperativeLevel,
7606 /*** Getters and setters **/
7607 IWineD3DDeviceImpl_SetClipPlane,
7608 IWineD3DDeviceImpl_GetClipPlane,
7609 IWineD3DDeviceImpl_SetClipStatus,
7610 IWineD3DDeviceImpl_GetClipStatus,
7611 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7612 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7613 IWineD3DDeviceImpl_SetDepthStencilSurface,
7614 IWineD3DDeviceImpl_GetDepthStencilSurface,
7615 IWineD3DDeviceImpl_SetFVF,
7616 IWineD3DDeviceImpl_GetFVF,
7617 IWineD3DDeviceImpl_SetGammaRamp,
7618 IWineD3DDeviceImpl_GetGammaRamp,
7619 IWineD3DDeviceImpl_SetIndices,
7620 IWineD3DDeviceImpl_GetIndices,
7621 IWineD3DDeviceImpl_SetBaseVertexIndex,
7622 IWineD3DDeviceImpl_GetBaseVertexIndex,
7623 IWineD3DDeviceImpl_SetLight,
7624 IWineD3DDeviceImpl_GetLight,
7625 IWineD3DDeviceImpl_SetLightEnable,
7626 IWineD3DDeviceImpl_GetLightEnable,
7627 IWineD3DDeviceImpl_SetMaterial,
7628 IWineD3DDeviceImpl_GetMaterial,
7629 IWineD3DDeviceImpl_SetNPatchMode,
7630 IWineD3DDeviceImpl_GetNPatchMode,
7631 IWineD3DDeviceImpl_SetPaletteEntries,
7632 IWineD3DDeviceImpl_GetPaletteEntries,
7633 IWineD3DDeviceImpl_SetPixelShader,
7634 IWineD3DDeviceImpl_GetPixelShader,
7635 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7636 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7637 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7638 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7639 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7640 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7641 IWineD3DDeviceImpl_SetRenderState,
7642 IWineD3DDeviceImpl_GetRenderState,
7643 IWineD3DDeviceImpl_SetRenderTarget,
7644 IWineD3DDeviceImpl_GetRenderTarget,
7645 IWineD3DDeviceImpl_SetFrontBackBuffers,
7646 IWineD3DDeviceImpl_SetSamplerState,
7647 IWineD3DDeviceImpl_GetSamplerState,
7648 IWineD3DDeviceImpl_SetScissorRect,
7649 IWineD3DDeviceImpl_GetScissorRect,
7650 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7651 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7652 IWineD3DDeviceImpl_SetStreamSource,
7653 IWineD3DDeviceImpl_GetStreamSource,
7654 IWineD3DDeviceImpl_SetStreamSourceFreq,
7655 IWineD3DDeviceImpl_GetStreamSourceFreq,
7656 IWineD3DDeviceImpl_SetTexture,
7657 IWineD3DDeviceImpl_GetTexture,
7658 IWineD3DDeviceImpl_SetTextureStageState,
7659 IWineD3DDeviceImpl_GetTextureStageState,
7660 IWineD3DDeviceImpl_SetTransform,
7661 IWineD3DDeviceImpl_GetTransform,
7662 IWineD3DDeviceImpl_SetVertexDeclaration,
7663 IWineD3DDeviceImpl_GetVertexDeclaration,
7664 IWineD3DDeviceImpl_SetVertexShader,
7665 IWineD3DDeviceImpl_GetVertexShader,
7666 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7667 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7668 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7669 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7670 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7671 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7672 IWineD3DDeviceImpl_SetViewport,
7673 IWineD3DDeviceImpl_GetViewport,
7674 IWineD3DDeviceImpl_MultiplyTransform,
7675 IWineD3DDeviceImpl_ValidateDevice,
7676 IWineD3DDeviceImpl_ProcessVertices,
7677 /*** State block ***/
7678 IWineD3DDeviceImpl_BeginStateBlock,
7679 IWineD3DDeviceImpl_EndStateBlock,
7680 /*** Scene management ***/
7681 IWineD3DDeviceImpl_BeginScene,
7682 IWineD3DDeviceImpl_EndScene,
7683 IWineD3DDeviceImpl_Present,
7684 IWineD3DDeviceImpl_Clear,
7686 IWineD3DDeviceImpl_DrawPrimitive,
7687 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7688 IWineD3DDeviceImpl_DrawPrimitiveUP,
7689 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7690 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7691 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7692 IWineD3DDeviceImpl_DrawRectPatch,
7693 IWineD3DDeviceImpl_DrawTriPatch,
7694 IWineD3DDeviceImpl_DeletePatch,
7695 IWineD3DDeviceImpl_ColorFill,
7696 IWineD3DDeviceImpl_UpdateTexture,
7697 IWineD3DDeviceImpl_UpdateSurface,
7698 IWineD3DDeviceImpl_GetFrontBufferData,
7699 /*** object tracking ***/
7700 IWineD3DDeviceImpl_ResourceReleased,
7701 IWineD3DDeviceImpl_EnumResources
7704 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7706 /*** IUnknown methods ***/
7707 IWineD3DDeviceImpl_QueryInterface,
7708 IWineD3DDeviceImpl_AddRef,
7709 IWineD3DDeviceImpl_Release,
7710 /*** IWineD3DDevice methods ***/
7711 IWineD3DDeviceImpl_GetParent,
7712 /*** Creation methods**/
7713 IWineD3DDeviceImpl_CreateVertexBuffer,
7714 IWineD3DDeviceImpl_CreateIndexBuffer,
7715 IWineD3DDeviceImpl_CreateStateBlock,
7716 IWineD3DDeviceImpl_CreateSurface,
7717 IWineD3DDeviceImpl_CreateTexture,
7718 IWineD3DDeviceImpl_CreateVolumeTexture,
7719 IWineD3DDeviceImpl_CreateVolume,
7720 IWineD3DDeviceImpl_CreateCubeTexture,
7721 IWineD3DDeviceImpl_CreateQuery,
7722 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7723 IWineD3DDeviceImpl_CreateVertexDeclaration,
7724 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7725 IWineD3DDeviceImpl_CreateVertexShader,
7726 IWineD3DDeviceImpl_CreatePixelShader,
7727 IWineD3DDeviceImpl_CreatePalette,
7728 /*** Odd functions **/
7729 IWineD3DDeviceImpl_Init3D,
7730 IWineD3DDeviceImpl_Uninit3D,
7731 IWineD3DDeviceImpl_SetFullscreen,
7732 IWineD3DDeviceImpl_SetMultithreaded,
7733 IWineD3DDeviceImpl_EvictManagedResources,
7734 IWineD3DDeviceImpl_GetAvailableTextureMem,
7735 IWineD3DDeviceImpl_GetBackBuffer,
7736 IWineD3DDeviceImpl_GetCreationParameters,
7737 IWineD3DDeviceImpl_GetDeviceCaps,
7738 IWineD3DDeviceImpl_GetDirect3D,
7739 IWineD3DDeviceImpl_GetDisplayMode,
7740 IWineD3DDeviceImpl_SetDisplayMode,
7741 IWineD3DDeviceImpl_GetHWND,
7742 IWineD3DDeviceImpl_SetHWND,
7743 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7744 IWineD3DDeviceImpl_GetRasterStatus,
7745 IWineD3DDeviceImpl_GetSwapChain,
7746 IWineD3DDeviceImpl_Reset,
7747 IWineD3DDeviceImpl_SetDialogBoxMode,
7748 IWineD3DDeviceImpl_SetCursorProperties,
7749 IWineD3DDeviceImpl_SetCursorPosition,
7750 IWineD3DDeviceImpl_ShowCursor,
7751 IWineD3DDeviceImpl_TestCooperativeLevel,
7752 /*** Getters and setters **/
7753 IWineD3DDeviceImpl_SetClipPlane,
7754 IWineD3DDeviceImpl_GetClipPlane,
7755 IWineD3DDeviceImpl_SetClipStatus,
7756 IWineD3DDeviceImpl_GetClipStatus,
7757 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7758 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7759 IWineD3DDeviceImpl_SetDepthStencilSurface,
7760 IWineD3DDeviceImpl_GetDepthStencilSurface,
7761 IWineD3DDeviceImpl_SetFVF,
7762 IWineD3DDeviceImpl_GetFVF,
7763 IWineD3DDeviceImpl_SetGammaRamp,
7764 IWineD3DDeviceImpl_GetGammaRamp,
7765 IWineD3DDeviceImpl_SetIndices,
7766 IWineD3DDeviceImpl_GetIndices,
7767 IWineD3DDeviceImpl_SetBaseVertexIndex,
7768 IWineD3DDeviceImpl_GetBaseVertexIndex,
7769 IWineD3DDeviceImpl_SetLight,
7770 IWineD3DDeviceImpl_GetLight,
7771 IWineD3DDeviceImpl_SetLightEnable,
7772 IWineD3DDeviceImpl_GetLightEnable,
7773 IWineD3DDeviceImpl_SetMaterial,
7774 IWineD3DDeviceImpl_GetMaterial,
7775 IWineD3DDeviceImpl_SetNPatchMode,
7776 IWineD3DDeviceImpl_GetNPatchMode,
7777 IWineD3DDeviceImpl_SetPaletteEntries,
7778 IWineD3DDeviceImpl_GetPaletteEntries,
7779 IWineD3DDeviceImpl_SetPixelShader,
7780 IWineD3DDeviceImpl_GetPixelShader,
7781 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7782 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7783 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7784 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7785 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7786 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7787 IWineD3DDeviceImpl_SetRenderState,
7788 IWineD3DDeviceImpl_GetRenderState,
7789 IWineD3DDeviceImpl_SetRenderTarget,
7790 IWineD3DDeviceImpl_GetRenderTarget,
7791 IWineD3DDeviceImpl_SetFrontBackBuffers,
7792 IWineD3DDeviceImpl_SetSamplerState,
7793 IWineD3DDeviceImpl_GetSamplerState,
7794 IWineD3DDeviceImpl_SetScissorRect,
7795 IWineD3DDeviceImpl_GetScissorRect,
7796 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7797 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7798 IWineD3DDeviceImpl_SetStreamSource,
7799 IWineD3DDeviceImpl_GetStreamSource,
7800 IWineD3DDeviceImpl_SetStreamSourceFreq,
7801 IWineD3DDeviceImpl_GetStreamSourceFreq,
7802 IWineD3DDeviceImpl_SetTexture,
7803 IWineD3DDeviceImpl_GetTexture,
7804 IWineD3DDeviceImpl_SetTextureStageState,
7805 IWineD3DDeviceImpl_GetTextureStageState,
7806 IWineD3DDeviceImpl_SetTransform,
7807 IWineD3DDeviceImpl_GetTransform,
7808 IWineD3DDeviceImpl_SetVertexDeclaration,
7809 IWineD3DDeviceImpl_GetVertexDeclaration,
7810 IWineD3DDeviceImpl_SetVertexShader,
7811 IWineD3DDeviceImpl_GetVertexShader,
7812 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7813 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7814 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7815 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7816 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7817 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7818 IWineD3DDeviceImpl_SetViewport,
7819 IWineD3DDeviceImpl_GetViewport,
7820 IWineD3DDeviceImpl_MultiplyTransform,
7821 IWineD3DDeviceImpl_ValidateDevice,
7822 IWineD3DDeviceImpl_ProcessVertices,
7823 /*** State block ***/
7824 IWineD3DDeviceImpl_BeginStateBlock,
7825 IWineD3DDeviceImpl_EndStateBlock,
7826 /*** Scene management ***/
7827 IWineD3DDeviceImpl_BeginScene,
7828 IWineD3DDeviceImpl_EndScene,
7829 IWineD3DDeviceImpl_Present,
7830 IWineD3DDeviceImpl_Clear,
7832 IWineD3DDeviceImpl_DrawPrimitive,
7833 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7834 IWineD3DDeviceImpl_DrawPrimitiveUP,
7835 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7836 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7837 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7838 IWineD3DDeviceImpl_DrawRectPatch,
7839 IWineD3DDeviceImpl_DrawTriPatch,
7840 IWineD3DDeviceImpl_DeletePatch,
7841 IWineD3DDeviceImpl_ColorFill,
7842 IWineD3DDeviceImpl_UpdateTexture,
7843 IWineD3DDeviceImpl_UpdateSurface,
7844 IWineD3DDeviceImpl_GetFrontBufferData,
7845 /*** object tracking ***/
7846 IWineD3DDeviceImpl_ResourceReleased,
7847 IWineD3DDeviceImpl_EnumResources
7850 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7851 WINED3DRS_ALPHABLENDENABLE ,
7852 WINED3DRS_ALPHAFUNC ,
7853 WINED3DRS_ALPHAREF ,
7854 WINED3DRS_ALPHATESTENABLE ,
7856 WINED3DRS_COLORWRITEENABLE ,
7857 WINED3DRS_DESTBLEND ,
7858 WINED3DRS_DITHERENABLE ,
7859 WINED3DRS_FILLMODE ,
7860 WINED3DRS_FOGDENSITY ,
7862 WINED3DRS_FOGSTART ,
7863 WINED3DRS_LASTPIXEL ,
7864 WINED3DRS_SHADEMODE ,
7865 WINED3DRS_SRCBLEND ,
7866 WINED3DRS_STENCILENABLE ,
7867 WINED3DRS_STENCILFAIL ,
7868 WINED3DRS_STENCILFUNC ,
7869 WINED3DRS_STENCILMASK ,
7870 WINED3DRS_STENCILPASS ,
7871 WINED3DRS_STENCILREF ,
7872 WINED3DRS_STENCILWRITEMASK ,
7873 WINED3DRS_STENCILZFAIL ,
7874 WINED3DRS_TEXTUREFACTOR ,
7885 WINED3DRS_ZWRITEENABLE
7888 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7889 WINED3DTSS_ADDRESSW ,
7890 WINED3DTSS_ALPHAARG0 ,
7891 WINED3DTSS_ALPHAARG1 ,
7892 WINED3DTSS_ALPHAARG2 ,
7893 WINED3DTSS_ALPHAOP ,
7894 WINED3DTSS_BUMPENVLOFFSET ,
7895 WINED3DTSS_BUMPENVLSCALE ,
7896 WINED3DTSS_BUMPENVMAT00 ,
7897 WINED3DTSS_BUMPENVMAT01 ,
7898 WINED3DTSS_BUMPENVMAT10 ,
7899 WINED3DTSS_BUMPENVMAT11 ,
7900 WINED3DTSS_COLORARG0 ,
7901 WINED3DTSS_COLORARG1 ,
7902 WINED3DTSS_COLORARG2 ,
7903 WINED3DTSS_COLOROP ,
7904 WINED3DTSS_RESULTARG ,
7905 WINED3DTSS_TEXCOORDINDEX ,
7906 WINED3DTSS_TEXTURETRANSFORMFLAGS
7909 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7910 WINED3DSAMP_ADDRESSU ,
7911 WINED3DSAMP_ADDRESSV ,
7912 WINED3DSAMP_ADDRESSW ,
7913 WINED3DSAMP_BORDERCOLOR ,
7914 WINED3DSAMP_MAGFILTER ,
7915 WINED3DSAMP_MINFILTER ,
7916 WINED3DSAMP_MIPFILTER ,
7917 WINED3DSAMP_MIPMAPLODBIAS ,
7918 WINED3DSAMP_MAXMIPLEVEL ,
7919 WINED3DSAMP_MAXANISOTROPY ,
7920 WINED3DSAMP_SRGBTEXTURE ,
7921 WINED3DSAMP_ELEMENTINDEX
7924 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7926 WINED3DRS_AMBIENTMATERIALSOURCE ,
7927 WINED3DRS_CLIPPING ,
7928 WINED3DRS_CLIPPLANEENABLE ,
7929 WINED3DRS_COLORVERTEX ,
7930 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7931 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7932 WINED3DRS_FOGDENSITY ,
7934 WINED3DRS_FOGSTART ,
7935 WINED3DRS_FOGTABLEMODE ,
7936 WINED3DRS_FOGVERTEXMODE ,
7937 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7938 WINED3DRS_LIGHTING ,
7939 WINED3DRS_LOCALVIEWER ,
7940 WINED3DRS_MULTISAMPLEANTIALIAS ,
7941 WINED3DRS_MULTISAMPLEMASK ,
7942 WINED3DRS_NORMALIZENORMALS ,
7943 WINED3DRS_PATCHEDGESTYLE ,
7944 WINED3DRS_POINTSCALE_A ,
7945 WINED3DRS_POINTSCALE_B ,
7946 WINED3DRS_POINTSCALE_C ,
7947 WINED3DRS_POINTSCALEENABLE ,
7948 WINED3DRS_POINTSIZE ,
7949 WINED3DRS_POINTSIZE_MAX ,
7950 WINED3DRS_POINTSIZE_MIN ,
7951 WINED3DRS_POINTSPRITEENABLE ,
7952 WINED3DRS_RANGEFOGENABLE ,
7953 WINED3DRS_SPECULARMATERIALSOURCE ,
7954 WINED3DRS_TWEENFACTOR ,
7955 WINED3DRS_VERTEXBLEND ,
7956 WINED3DRS_CULLMODE ,
7960 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7961 WINED3DTSS_TEXCOORDINDEX ,
7962 WINED3DTSS_TEXTURETRANSFORMFLAGS
7965 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7966 WINED3DSAMP_DMAPOFFSET
7969 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7970 DWORD rep = This->shader_backend->StateTable[state].representative;
7974 WineD3DContext *context;
7977 for(i = 0; i < This->numContexts; i++) {
7978 context = This->contexts[i];
7979 if(isStateDirty(context, rep)) continue;
7981 context->dirtyArray[context->numDirtyEntries++] = rep;
7984 context->isStateDirty[idx] |= (1 << shift);
7988 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7989 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7990 /* The drawable size of a pbuffer render target is the current pbuffer size
7992 *width = dev->pbufferWidth;
7993 *height = dev->pbufferHeight;
7996 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7997 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7999 *width = This->pow2Width;
8000 *height = This->pow2Height;
8003 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8004 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8005 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8006 * current context's drawable, which is the size of the back buffer of the swapchain
8007 * the active context belongs to. The back buffer of the swapchain is stored as the
8008 * surface the context belongs to.
8010 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8011 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;