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 /* TODO: It should only be possible to create textures for formats
776 that are reported as supported */
777 if (WINED3DFMT_UNKNOWN >= Format) {
778 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
779 return WINED3DERR_INVALIDCALL;
782 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
783 D3DINITIALIZEBASETEXTURE(object->baseTexture);
784 object->width = Width;
785 object->height = Height;
787 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
788 object->baseTexture.minMipLookup = &minMipLookup;
789 object->baseTexture.magLookup = &magLookup;
791 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
792 object->baseTexture.magLookup = &magLookup_noFilter;
795 /** Non-power2 support **/
796 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
800 /* Find the nearest pow2 match */
801 pow2Width = pow2Height = 1;
802 while (pow2Width < Width) pow2Width <<= 1;
803 while (pow2Height < Height) pow2Height <<= 1;
805 if(pow2Width != Width || pow2Height != Height) {
807 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
808 HeapFree(GetProcessHeap(), 0, object);
810 return WINED3DERR_INVALIDCALL;
817 /** FIXME: add support for real non-power-two if it's provided by the video card **/
818 /* Precalculated scaling for 'faked' non power of two texture coords.
819 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
820 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
821 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
823 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
824 (Width != pow2Width || Height != pow2Height) &&
825 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
827 object->baseTexture.pow2Matrix[0] = (float)Width;
828 object->baseTexture.pow2Matrix[5] = (float)Height;
829 object->baseTexture.pow2Matrix[10] = 1.0;
830 object->baseTexture.pow2Matrix[15] = 1.0;
831 object->target = GL_TEXTURE_RECTANGLE_ARB;
833 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
834 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_2D;
839 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
841 /* Calculate levels for mip mapping */
842 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
843 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
844 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
845 return WINED3DERR_INVALIDCALL;
848 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
849 return WINED3DERR_INVALIDCALL;
851 object->baseTexture.levels = 1;
852 } else if (Levels == 0) {
853 TRACE("calculating levels %d\n", object->baseTexture.levels);
854 object->baseTexture.levels++;
857 while (tmpW > 1 || tmpH > 1) {
858 tmpW = max(1, tmpW >> 1);
859 tmpH = max(1, tmpH >> 1);
860 object->baseTexture.levels++;
862 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
865 /* Generate all the surfaces */
868 for (i = 0; i < object->baseTexture.levels; i++)
870 /* use the callback to create the texture surface */
871 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
872 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
873 FIXME("Failed to create surface %p\n", object);
875 object->surfaces[i] = NULL;
876 IWineD3DTexture_Release((IWineD3DTexture *)object);
882 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
883 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
884 /* calculate the next mipmap level */
885 tmpW = max(1, tmpW >> 1);
886 tmpH = max(1, tmpH >> 1);
888 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
890 TRACE("(%p) : Created texture %p\n", This, object);
894 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
895 UINT Width, UINT Height, UINT Depth,
896 UINT Levels, DWORD Usage,
897 WINED3DFORMAT Format, WINED3DPOOL Pool,
898 IWineD3DVolumeTexture **ppVolumeTexture,
899 HANDLE *pSharedHandle, IUnknown *parent,
900 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
903 IWineD3DVolumeTextureImpl *object;
908 const GlPixelFormatDesc *glDesc;
910 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
912 /* TODO: It should only be possible to create textures for formats
913 that are reported as supported */
914 if (WINED3DFMT_UNKNOWN >= Format) {
915 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
916 return WINED3DERR_INVALIDCALL;
918 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
919 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
920 return WINED3DERR_INVALIDCALL;
923 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
924 D3DINITIALIZEBASETEXTURE(object->baseTexture);
926 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
927 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
929 object->width = Width;
930 object->height = Height;
931 object->depth = Depth;
933 /* Is NP2 support for volumes needed? */
934 object->baseTexture.pow2Matrix[ 0] = 1.0;
935 object->baseTexture.pow2Matrix[ 5] = 1.0;
936 object->baseTexture.pow2Matrix[10] = 1.0;
937 object->baseTexture.pow2Matrix[15] = 1.0;
939 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
940 object->baseTexture.minMipLookup = &minMipLookup;
941 object->baseTexture.magLookup = &magLookup;
943 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
944 object->baseTexture.magLookup = &magLookup_noFilter;
947 /* Calculate levels for mip mapping */
948 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
949 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
950 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
951 return WINED3DERR_INVALIDCALL;
954 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
955 return WINED3DERR_INVALIDCALL;
958 } else if (Levels == 0) {
959 object->baseTexture.levels++;
963 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
964 tmpW = max(1, tmpW >> 1);
965 tmpH = max(1, tmpH >> 1);
966 tmpD = max(1, tmpD >> 1);
967 object->baseTexture.levels++;
969 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
972 /* Generate all the surfaces */
977 for (i = 0; i < object->baseTexture.levels; i++)
980 /* Create the volume */
981 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
982 &object->volumes[i], pSharedHandle);
985 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
986 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
987 *ppVolumeTexture = NULL;
991 /* Set its container to this object */
992 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
994 /* calculate the next mipmap level */
995 tmpW = max(1, tmpW >> 1);
996 tmpH = max(1, tmpH >> 1);
997 tmpD = max(1, tmpD >> 1);
999 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1001 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1002 TRACE("(%p) : Created volume texture %p\n", This, object);
1006 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1007 UINT Width, UINT Height, UINT Depth,
1009 WINED3DFORMAT Format, WINED3DPOOL Pool,
1010 IWineD3DVolume** ppVolume,
1011 HANDLE* pSharedHandle, IUnknown *parent) {
1013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1014 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1015 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1017 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1018 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1019 return WINED3DERR_INVALIDCALL;
1022 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1024 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1025 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1027 object->currentDesc.Width = Width;
1028 object->currentDesc.Height = Height;
1029 object->currentDesc.Depth = Depth;
1030 object->bytesPerPixel = formatDesc->bpp;
1032 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1033 object->lockable = TRUE;
1034 object->locked = FALSE;
1035 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1036 object->dirty = TRUE;
1038 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1041 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1042 UINT Levels, DWORD Usage,
1043 WINED3DFORMAT Format, WINED3DPOOL Pool,
1044 IWineD3DCubeTexture **ppCubeTexture,
1045 HANDLE *pSharedHandle, IUnknown *parent,
1046 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1048 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1049 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1053 unsigned int pow2EdgeLength = EdgeLength;
1054 const GlPixelFormatDesc *glDesc;
1055 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1057 /* TODO: It should only be possible to create textures for formats
1058 that are reported as supported */
1059 if (WINED3DFMT_UNKNOWN >= Format) {
1060 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1061 return WINED3DERR_INVALIDCALL;
1064 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1065 WARN("(%p) : Tried to create not supported cube texture\n", This);
1066 return WINED3DERR_INVALIDCALL;
1069 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1070 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1072 TRACE("(%p) Create Cube Texture\n", This);
1074 /** Non-power2 support **/
1076 /* Find the nearest pow2 match */
1078 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1080 object->edgeLength = EdgeLength;
1081 /* TODO: support for native non-power 2 */
1082 /* Precalculated scaling for 'faked' non power of two texture coords */
1083 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1086 object->baseTexture.pow2Matrix[15] = 1.0;
1088 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1089 object->baseTexture.minMipLookup = &minMipLookup;
1090 object->baseTexture.magLookup = &magLookup;
1092 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1093 object->baseTexture.magLookup = &magLookup_noFilter;
1096 /* Calculate levels for mip mapping */
1097 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1098 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1099 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1100 HeapFree(GetProcessHeap(), 0, object);
1101 *ppCubeTexture = NULL;
1103 return WINED3DERR_INVALIDCALL;
1106 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1107 HeapFree(GetProcessHeap(), 0, object);
1108 *ppCubeTexture = NULL;
1110 return WINED3DERR_INVALIDCALL;
1113 } else if (Levels == 0) {
1114 object->baseTexture.levels++;
1117 tmpW = max(1, tmpW >> 1);
1118 object->baseTexture.levels++;
1120 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1123 /* Generate all the surfaces */
1125 for (i = 0; i < object->baseTexture.levels; i++) {
1127 /* Create the 6 faces */
1128 for (j = 0; j < 6; j++) {
1130 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1131 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1133 if(hr!= WINED3D_OK) {
1137 for (l = 0; l < j; l++) {
1138 IWineD3DSurface_Release(object->surfaces[l][i]);
1140 for (k = 0; k < i; k++) {
1141 for (l = 0; l < 6; l++) {
1142 IWineD3DSurface_Release(object->surfaces[l][k]);
1146 FIXME("(%p) Failed to create surface\n",object);
1147 HeapFree(GetProcessHeap(),0,object);
1148 *ppCubeTexture = NULL;
1151 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1152 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1154 tmpW = max(1, tmpW >> 1);
1156 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1158 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1159 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1163 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1165 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1166 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1167 const IWineD3DQueryVtbl *vtable;
1169 /* Just a check to see if we support this type of query */
1171 case WINED3DQUERYTYPE_OCCLUSION:
1172 TRACE("(%p) occlusion query\n", This);
1173 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1176 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1178 vtable = &IWineD3DOcclusionQuery_Vtbl;
1181 case WINED3DQUERYTYPE_EVENT:
1182 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1183 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1184 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1186 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1188 vtable = &IWineD3DEventQuery_Vtbl;
1192 case WINED3DQUERYTYPE_VCACHE:
1193 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1194 case WINED3DQUERYTYPE_VERTEXSTATS:
1195 case WINED3DQUERYTYPE_TIMESTAMP:
1196 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1197 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1198 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1199 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1200 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1201 case WINED3DQUERYTYPE_PIXELTIMINGS:
1202 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1203 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1205 /* Use the base Query vtable until we have a special one for each query */
1206 vtable = &IWineD3DQuery_Vtbl;
1207 FIXME("(%p) Unhandled query type %d\n", This, Type);
1209 if(NULL == ppQuery || hr != WINED3D_OK) {
1213 D3DCREATEOBJECTINSTANCE(object, Query)
1214 object->lpVtbl = vtable;
1215 object->type = Type;
1216 object->state = QUERY_CREATED;
1217 /* allocated the 'extended' data based on the type of query requested */
1219 case WINED3DQUERYTYPE_OCCLUSION:
1220 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1221 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1223 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1224 TRACE("(%p) Allocating data for an occlusion query\n", This);
1225 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1228 case WINED3DQUERYTYPE_EVENT:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1230 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1232 if(GL_SUPPORT(APPLE_FENCE)) {
1233 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1234 checkGLcall("glGenFencesAPPLE");
1235 } else if(GL_SUPPORT(NV_FENCE)) {
1236 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1237 checkGLcall("glGenFencesNV");
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1254 object->extendedData = 0;
1255 FIXME("(%p) Unhandled query type %d\n",This , Type);
1257 TRACE("(%p) : Created Query %p\n", This, object);
1261 /*****************************************************************************
1262 * IWineD3DDeviceImpl_SetupFullscreenWindow
1264 * Helper function that modifies a HWND's Style and ExStyle for proper
1268 * iface: Pointer to the IWineD3DDevice interface
1269 * window: Window to setup
1271 *****************************************************************************/
1272 static LONG fullscreen_style(LONG orig_style) {
1273 LONG style = orig_style;
1274 style &= ~WS_CAPTION;
1275 style &= ~WS_THICKFRAME;
1277 /* Make sure the window is managed, otherwise we won't get keyboard input */
1278 style |= WS_POPUP | WS_SYSMENU;
1283 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1284 LONG exStyle = orig_exStyle;
1286 /* Filter out window decorations */
1287 exStyle &= ~WS_EX_WINDOWEDGE;
1288 exStyle &= ~WS_EX_CLIENTEDGE;
1293 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 LONG style, exStyle;
1297 /* Don't do anything if an original style is stored.
1298 * That shouldn't happen
1300 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1301 if (This->style || This->exStyle) {
1302 ERR("(%p): Want to change the window parameters of HWND %p, but "
1303 "another style is stored for restoration afterwards\n", This, window);
1306 /* Get the parameters and save them */
1307 style = GetWindowLongW(window, GWL_STYLE);
1308 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1309 This->style = style;
1310 This->exStyle = exStyle;
1312 style = fullscreen_style(style);
1313 exStyle = fullscreen_exStyle(exStyle);
1315 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1316 This->style, This->exStyle, style, exStyle);
1318 SetWindowLongW(window, GWL_STYLE, style);
1319 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1321 /* Inform the window about the update. */
1322 SetWindowPos(window, HWND_TOP, 0, 0,
1323 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1324 ShowWindow(window, SW_NORMAL);
1327 /*****************************************************************************
1328 * IWineD3DDeviceImpl_RestoreWindow
1330 * Helper function that restores a windows' properties when taking it out
1331 * of fullscreen mode
1334 * iface: Pointer to the IWineD3DDevice interface
1335 * window: Window to setup
1337 *****************************************************************************/
1338 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1340 LONG style, exStyle;
1342 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1343 * switch, do nothing
1345 if (!This->style && !This->exStyle) return;
1347 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1348 This, window, This->style, This->exStyle);
1350 style = GetWindowLongW(window, GWL_STYLE);
1351 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1353 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1354 * Some applications change it before calling Reset() when switching between windowed and
1355 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1357 if(style == fullscreen_style(This->style) &&
1358 exStyle == fullscreen_style(This->exStyle)) {
1359 SetWindowLongW(window, GWL_STYLE, This->style);
1360 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1363 /* Delete the old values */
1367 /* Inform the window about the update */
1368 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1369 0, 0, 0, 0, /* Pos, Size, ignored */
1370 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1373 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1374 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1376 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1377 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1381 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1382 HRESULT hr = WINED3D_OK;
1383 IUnknown *bufferParent;
1384 BOOL displaymode_set = FALSE;
1385 WINED3DDISPLAYMODE Mode;
1386 const StaticPixelFormatDesc *formatDesc;
1388 TRACE("(%p) : Created Additional Swap Chain\n", This);
1390 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1391 * does a device hold a reference to a swap chain giving them a lifetime of the device
1392 * or does the swap chain notify the device of its destruction.
1393 *******************************/
1395 /* Check the params */
1396 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1397 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1398 return WINED3DERR_INVALIDCALL;
1399 } else if (pPresentationParameters->BackBufferCount > 1) {
1400 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");
1403 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1405 /*********************
1406 * Lookup the window Handle and the relating X window handle
1407 ********************/
1409 /* Setup hwnd we are using, plus which display this equates to */
1410 object->win_handle = pPresentationParameters->hDeviceWindow;
1411 if (!object->win_handle) {
1412 object->win_handle = This->createParms.hFocusWindow;
1414 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1416 hDc = GetDC(object->win_handle);
1417 TRACE("Using hDc %p\n", hDc);
1420 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1421 return WINED3DERR_NOTAVAILABLE;
1424 /* Get info on the current display setup */
1425 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1426 object->orig_width = Mode.Width;
1427 object->orig_height = Mode.Height;
1428 object->orig_fmt = Mode.Format;
1429 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1431 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1432 * then the corresponding dimension of the client area of the hDeviceWindow
1433 * (or the focus window, if hDeviceWindow is NULL) is taken.
1434 **********************/
1436 if (pPresentationParameters->Windowed &&
1437 ((pPresentationParameters->BackBufferWidth == 0) ||
1438 (pPresentationParameters->BackBufferHeight == 0) ||
1439 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1442 GetClientRect(object->win_handle, &Rect);
1444 if (pPresentationParameters->BackBufferWidth == 0) {
1445 pPresentationParameters->BackBufferWidth = Rect.right;
1446 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1448 if (pPresentationParameters->BackBufferHeight == 0) {
1449 pPresentationParameters->BackBufferHeight = Rect.bottom;
1450 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1452 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1453 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1454 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1458 /* Put the correct figures in the presentation parameters */
1459 TRACE("Copying across presentation parameters\n");
1460 object->presentParms = *pPresentationParameters;
1462 TRACE("calling rendertarget CB\n");
1463 hr = D3DCB_CreateRenderTarget(This->parent,
1465 object->presentParms.BackBufferWidth,
1466 object->presentParms.BackBufferHeight,
1467 object->presentParms.BackBufferFormat,
1468 object->presentParms.MultiSampleType,
1469 object->presentParms.MultiSampleQuality,
1470 TRUE /* Lockable */,
1471 &object->frontBuffer,
1472 NULL /* pShared (always null)*/);
1473 if (object->frontBuffer != NULL) {
1474 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1475 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1477 ERR("Failed to create the front buffer\n");
1481 /*********************
1482 * Windowed / Fullscreen
1483 *******************/
1486 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1487 * so we should really check to see if there is a fullscreen swapchain already
1488 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1489 **************************************/
1491 if (!pPresentationParameters->Windowed) {
1492 WINED3DDISPLAYMODE mode;
1495 /* Change the display settings */
1496 mode.Width = pPresentationParameters->BackBufferWidth;
1497 mode.Height = pPresentationParameters->BackBufferHeight;
1498 mode.Format = pPresentationParameters->BackBufferFormat;
1499 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1501 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1502 displaymode_set = TRUE;
1503 IWineD3DDevice_SetFullscreen(iface, TRUE);
1507 * Create an opengl context for the display visual
1508 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1509 * use different properties after that point in time. FIXME: How to handle when requested format
1510 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1511 * it chooses is identical to the one already being used!
1512 **********************************/
1513 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1515 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1516 if(!object->context)
1517 return E_OUTOFMEMORY;
1518 object->num_contexts = 1;
1520 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1521 if (!object->context[0]) {
1522 ERR("Failed to create a new context\n");
1523 hr = WINED3DERR_NOTAVAILABLE;
1526 TRACE("Context created (HWND=%p, glContext=%p)\n",
1527 object->win_handle, object->context[0]->glCtx);
1530 /*********************
1531 * Create the back, front and stencil buffers
1532 *******************/
1533 if(object->presentParms.BackBufferCount > 0) {
1536 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1537 if(!object->backBuffer) {
1538 ERR("Out of memory\n");
1543 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1544 TRACE("calling rendertarget CB\n");
1545 hr = D3DCB_CreateRenderTarget(This->parent,
1547 object->presentParms.BackBufferWidth,
1548 object->presentParms.BackBufferHeight,
1549 object->presentParms.BackBufferFormat,
1550 object->presentParms.MultiSampleType,
1551 object->presentParms.MultiSampleQuality,
1552 TRUE /* Lockable */,
1553 &object->backBuffer[i],
1554 NULL /* pShared (always null)*/);
1555 if(hr == WINED3D_OK && object->backBuffer[i]) {
1556 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1558 ERR("Cannot create new back buffer\n");
1562 glDrawBuffer(GL_BACK);
1563 checkGLcall("glDrawBuffer(GL_BACK)");
1567 object->backBuffer = NULL;
1569 /* Single buffering - draw to front buffer */
1571 glDrawBuffer(GL_FRONT);
1572 checkGLcall("glDrawBuffer(GL_FRONT)");
1576 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1577 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1578 TRACE("Creating depth stencil buffer\n");
1579 if (This->auto_depth_stencil_buffer == NULL ) {
1580 hr = D3DCB_CreateDepthStencil(This->parent,
1582 object->presentParms.BackBufferWidth,
1583 object->presentParms.BackBufferHeight,
1584 object->presentParms.AutoDepthStencilFormat,
1585 object->presentParms.MultiSampleType,
1586 object->presentParms.MultiSampleQuality,
1587 FALSE /* FIXME: Discard */,
1588 &This->auto_depth_stencil_buffer,
1589 NULL /* pShared (always null)*/ );
1590 if (This->auto_depth_stencil_buffer != NULL)
1591 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1594 /** TODO: A check on width, height and multisample types
1595 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1596 ****************************/
1597 object->wantsDepthStencilBuffer = TRUE;
1599 object->wantsDepthStencilBuffer = FALSE;
1602 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1604 TRACE("Created swapchain %p\n", object);
1605 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1609 if (displaymode_set) {
1613 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1616 /* Change the display settings */
1617 memset(&devmode, 0, sizeof(devmode));
1618 devmode.dmSize = sizeof(devmode);
1619 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1620 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1621 devmode.dmPelsWidth = object->orig_width;
1622 devmode.dmPelsHeight = object->orig_height;
1623 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1626 if (object->backBuffer) {
1628 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1629 if(object->backBuffer[i]) {
1630 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1631 IUnknown_Release(bufferParent); /* once for the get parent */
1632 if (IUnknown_Release(bufferParent) > 0) {
1633 FIXME("(%p) Something's still holding the back buffer\n",This);
1637 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1638 object->backBuffer = NULL;
1640 if(object->context[0])
1641 DestroyContext(This, object->context[0]);
1642 if(object->frontBuffer) {
1643 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1644 IUnknown_Release(bufferParent); /* once for the get parent */
1645 if (IUnknown_Release(bufferParent) > 0) {
1646 FIXME("(%p) Something's still holding the front buffer\n",This);
1649 HeapFree(GetProcessHeap(), 0, object);
1653 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1654 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1656 TRACE("(%p)\n", This);
1658 return This->NumberOfSwapChains;
1661 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1662 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1663 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1665 if(iSwapChain < This->NumberOfSwapChains) {
1666 *pSwapChain = This->swapchains[iSwapChain];
1667 IWineD3DSwapChain_AddRef(*pSwapChain);
1668 TRACE("(%p) returning %p\n", This, *pSwapChain);
1671 TRACE("Swapchain out of range\n");
1673 return WINED3DERR_INVALIDCALL;
1678 * Vertex Declaration
1680 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1681 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1682 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1683 IWineD3DVertexDeclarationImpl *object = NULL;
1684 HRESULT hr = WINED3D_OK;
1686 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1687 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1689 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1691 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1693 *ppVertexDeclaration = NULL;
1694 HeapFree(GetProcessHeap(), 0, object);
1700 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1701 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1703 unsigned int idx, idx2;
1704 unsigned int offset;
1705 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1706 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1707 BOOL has_blend_idx = has_blend &&
1708 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1709 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1710 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1711 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1712 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1713 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1714 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1716 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1717 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1719 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1720 WINED3DVERTEXELEMENT *elements = NULL;
1723 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1724 if (has_blend_idx) num_blends--;
1726 /* Compute declaration size */
1727 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1728 has_psize + has_diffuse + has_specular + num_textures + 1;
1730 /* convert the declaration */
1731 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1735 elements[size-1] = end_element;
1738 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1739 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1740 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1743 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1744 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1746 elements[idx].UsageIndex = 0;
1749 if (has_blend && (num_blends > 0)) {
1750 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1751 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1754 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1755 elements[idx].UsageIndex = 0;
1758 if (has_blend_idx) {
1759 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1760 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1761 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1762 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1763 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1766 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1767 elements[idx].UsageIndex = 0;
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1772 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1773 elements[idx].UsageIndex = 0;
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1778 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1779 elements[idx].UsageIndex = 0;
1783 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1784 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1785 elements[idx].UsageIndex = 0;
1789 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1790 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1791 elements[idx].UsageIndex = 1;
1794 for (idx2 = 0; idx2 < num_textures; idx2++) {
1795 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1796 switch (numcoords) {
1797 case WINED3DFVF_TEXTUREFORMAT1:
1798 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 case WINED3DFVF_TEXTUREFORMAT2:
1801 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1803 case WINED3DFVF_TEXTUREFORMAT3:
1804 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1806 case WINED3DFVF_TEXTUREFORMAT4:
1807 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1810 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1811 elements[idx].UsageIndex = idx2;
1815 /* Now compute offsets, and initialize the rest of the fields */
1816 for (idx = 0, offset = 0; idx < size-1; idx++) {
1817 elements[idx].Stream = 0;
1818 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1819 elements[idx].Offset = offset;
1820 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1823 *ppVertexElements = elements;
1827 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1828 WINED3DVERTEXELEMENT* elements = NULL;
1829 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1833 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1834 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1836 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1837 HeapFree(GetProcessHeap(), 0, elements);
1838 if (hr != S_OK) return hr;
1843 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1845 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1846 HRESULT hr = WINED3D_OK;
1847 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1848 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1850 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1852 if (vertex_declaration) {
1853 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1856 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1858 if (WINED3D_OK != hr) {
1859 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1860 IWineD3DVertexShader_Release(*ppVertexShader);
1861 return WINED3DERR_INVALIDCALL;
1863 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1868 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1870 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1871 HRESULT hr = WINED3D_OK;
1873 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1874 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1875 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1876 if (WINED3D_OK == hr) {
1877 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1878 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1880 WARN("(%p) : Failed to create pixel shader\n", This);
1886 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1888 IWineD3DPaletteImpl *object;
1890 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1892 /* Create the new object */
1893 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1895 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1896 return E_OUTOFMEMORY;
1899 object->lpVtbl = &IWineD3DPalette_Vtbl;
1901 object->Flags = Flags;
1902 object->parent = Parent;
1903 object->wineD3DDevice = This;
1904 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1906 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1909 HeapFree( GetProcessHeap(), 0, object);
1910 return E_OUTOFMEMORY;
1913 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1915 IWineD3DPalette_Release((IWineD3DPalette *) object);
1919 *Palette = (IWineD3DPalette *) object;
1924 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1928 HDC dcb = NULL, dcs = NULL;
1929 WINEDDCOLORKEY colorkey;
1931 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1934 GetObjectA(hbm, sizeof(BITMAP), &bm);
1935 dcb = CreateCompatibleDC(NULL);
1937 SelectObject(dcb, hbm);
1941 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1942 * couldn't be loaded
1944 memset(&bm, 0, sizeof(bm));
1949 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1950 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1951 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1953 ERR("Wine logo requested, but failed to create surface\n");
1958 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1959 if(FAILED(hr)) goto out;
1960 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1961 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1963 colorkey.dwColorSpaceLowValue = 0;
1964 colorkey.dwColorSpaceHighValue = 0;
1965 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1967 /* Fill the surface with a white color to show that wined3d is there */
1968 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1981 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1983 /* Under DirectX you can have texture stage operations even if no texture is
1984 bound, whereas opengl will only do texture operations when a valid texture is
1985 bound. We emulate this by creating dummy textures and binding them to each
1986 texture stage, but disable all stages by default. Hence if a stage is enabled
1987 then the default texture will kick in until replaced by a SetTexture call */
1990 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
1991 /* The dummy texture does not have client storage backing */
1992 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
1993 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
1995 for (i = 0; i < GL_LIMITS(textures); i++) {
1996 GLubyte white = 255;
1998 /* Make appropriate texture active */
1999 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2000 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2001 checkGLcall("glActiveTextureARB");
2003 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2006 /* Generate an opengl texture name */
2007 glGenTextures(1, &This->dummyTextureName[i]);
2008 checkGLcall("glGenTextures");
2009 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2011 /* Generate a dummy 2d texture (not using 1d because they cause many
2012 * DRI drivers fall back to sw) */
2013 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2014 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2015 checkGLcall("glBindTexture");
2017 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2018 checkGLcall("glTexImage2D");
2020 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2021 /* Reenable because if supported it is enabled by default */
2022 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2023 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2029 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2031 IWineD3DSwapChainImpl *swapchain = NULL;
2036 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2037 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2038 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2040 /* TODO: Test if OpenGL is compiled in and loaded */
2042 TRACE("(%p) : Creating stateblock\n", This);
2043 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2044 hr = IWineD3DDevice_CreateStateBlock(iface,
2046 (IWineD3DStateBlock **)&This->stateBlock,
2048 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2049 WARN("Failed to create stateblock\n");
2052 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2053 This->updateStateBlock = This->stateBlock;
2054 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2056 hr = allocate_shader_constants(This->updateStateBlock);
2057 if (WINED3D_OK != hr) {
2061 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2062 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2063 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2065 This->NumberOfPalettes = 1;
2066 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2067 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2068 ERR("Out of memory!\n");
2071 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2072 if(!This->palettes[0]) {
2073 ERR("Out of memory!\n");
2076 for (i = 0; i < 256; ++i) {
2077 This->palettes[0][i].peRed = 0xFF;
2078 This->palettes[0][i].peGreen = 0xFF;
2079 This->palettes[0][i].peBlue = 0xFF;
2080 This->palettes[0][i].peFlags = 0xFF;
2082 This->currentPalette = 0;
2084 /* Initialize the texture unit mapping to a 1:1 mapping */
2085 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2086 if (state < GL_LIMITS(fragment_samplers)) {
2087 This->texUnitMap[state] = state;
2088 This->rev_tex_unit_map[state] = state;
2090 This->texUnitMap[state] = -1;
2091 This->rev_tex_unit_map[state] = -1;
2095 /* Setup the implicit swapchain */
2096 TRACE("Creating implicit swapchain\n");
2097 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2098 if (FAILED(hr) || !swapchain) {
2099 WARN("Failed to create implicit swapchain\n");
2103 This->NumberOfSwapChains = 1;
2104 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2105 if(!This->swapchains) {
2106 ERR("Out of memory!\n");
2109 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2111 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2112 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2113 This->render_targets[0] = swapchain->backBuffer[0];
2114 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2117 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2118 This->render_targets[0] = swapchain->frontBuffer;
2119 This->lastActiveRenderTarget = swapchain->frontBuffer;
2121 IWineD3DSurface_AddRef(This->render_targets[0]);
2122 This->activeContext = swapchain->context[0];
2123 This->lastThread = GetCurrentThreadId();
2125 /* Depth Stencil support */
2126 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2127 if (NULL != This->stencilBufferTarget) {
2128 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2131 hr = This->shader_backend->shader_alloc_private(iface);
2133 TRACE("Shader private data couldn't be allocated\n");
2137 /* Set up some starting GL setup */
2139 /* Setup all the devices defaults */
2140 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2141 create_dummy_textures(This);
2146 IWineD3DImpl_CheckGraphicsMemory();
2149 { /* Set a default viewport */
2153 vp.Width = pPresentationParameters->BackBufferWidth;
2154 vp.Height = pPresentationParameters->BackBufferHeight;
2157 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2160 /* Initialize the current view state */
2161 This->view_ident = 1;
2162 This->contexts[0]->last_was_rhw = 0;
2163 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2164 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2166 switch(wined3d_settings.offscreen_rendering_mode) {
2169 This->offscreenBuffer = GL_BACK;
2172 case ORM_BACKBUFFER:
2174 if(This->activeContext->aux_buffers > 0) {
2175 TRACE("Using auxilliary buffer for offscreen rendering\n");
2176 This->offscreenBuffer = GL_AUX0;
2178 TRACE("Using back buffer for offscreen rendering\n");
2179 This->offscreenBuffer = GL_BACK;
2184 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2187 /* Clear the screen */
2188 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2189 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2192 This->d3d_initialized = TRUE;
2194 if(wined3d_settings.logo) {
2195 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2197 This->highest_dirty_ps_const = 0;
2198 This->highest_dirty_vs_const = 0;
2202 This->shader_backend->shader_free_private(iface);
2203 HeapFree(GetProcessHeap(), 0, This->render_targets);
2204 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2205 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2206 HeapFree(GetProcessHeap(), 0, This->swapchains);
2207 This->NumberOfSwapChains = 0;
2208 if(This->palettes) {
2209 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2210 HeapFree(GetProcessHeap(), 0, This->palettes);
2212 This->NumberOfPalettes = 0;
2214 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2216 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2217 if(This->stateBlock) {
2218 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2219 This->stateBlock = NULL;
2224 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2228 TRACE("(%p)\n", This);
2230 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2232 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2233 * it was created. Thus make sure a context is active for the glDelete* calls
2235 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2237 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2239 TRACE("Deleting high order patches\n");
2240 for(i = 0; i < PATCHMAP_SIZE; i++) {
2241 struct list *e1, *e2;
2242 struct WineD3DRectPatch *patch;
2243 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2244 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2245 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2249 /* Delete the palette conversion shader if it is around */
2250 if(This->paletteConversionShader) {
2252 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2254 This->paletteConversionShader = 0;
2257 /* Delete the pbuffer context if there is any */
2258 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2260 /* Delete the mouse cursor texture */
2261 if(This->cursorTexture) {
2263 glDeleteTextures(1, &This->cursorTexture);
2265 This->cursorTexture = 0;
2268 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2269 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2271 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2272 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2275 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2276 * private data, it might contain opengl pointers
2278 if(This->depth_blt_texture) {
2279 glDeleteTextures(1, &This->depth_blt_texture);
2280 This->depth_blt_texture = 0;
2282 if (This->depth_blt_rb) {
2283 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2284 This->depth_blt_rb = 0;
2285 This->depth_blt_rb_w = 0;
2286 This->depth_blt_rb_h = 0;
2288 This->shader_backend->shader_destroy_depth_blt(iface);
2289 This->shader_backend->shader_free_private(iface);
2291 /* Release the update stateblock */
2292 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2293 if(This->updateStateBlock != This->stateBlock)
2294 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2296 This->updateStateBlock = NULL;
2298 { /* because were not doing proper internal refcounts releasing the primary state block
2299 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2300 to set this->stateBlock = NULL; first */
2301 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2302 This->stateBlock = NULL;
2304 /* Release the stateblock */
2305 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2306 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2310 /* Release the buffers (with sanity checks)*/
2311 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2312 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2313 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2314 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2316 This->stencilBufferTarget = NULL;
2318 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2319 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2320 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2322 TRACE("Setting rendertarget to NULL\n");
2323 This->render_targets[0] = NULL;
2325 if (This->auto_depth_stencil_buffer) {
2326 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2327 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2329 This->auto_depth_stencil_buffer = NULL;
2332 for(i=0; i < This->NumberOfSwapChains; i++) {
2333 TRACE("Releasing the implicit swapchain %d\n", i);
2334 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2335 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2339 HeapFree(GetProcessHeap(), 0, This->swapchains);
2340 This->swapchains = NULL;
2341 This->NumberOfSwapChains = 0;
2343 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2344 HeapFree(GetProcessHeap(), 0, This->palettes);
2345 This->palettes = NULL;
2346 This->NumberOfPalettes = 0;
2348 HeapFree(GetProcessHeap(), 0, This->render_targets);
2349 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2350 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2351 This->render_targets = NULL;
2352 This->fbo_color_attachments = NULL;
2353 This->draw_buffers = NULL;
2355 This->d3d_initialized = FALSE;
2359 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2361 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2363 /* Setup the window for fullscreen mode */
2364 if(fullscreen && !This->ddraw_fullscreen) {
2365 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2366 } else if(!fullscreen && This->ddraw_fullscreen) {
2367 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2370 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2371 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2372 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2375 This->ddraw_fullscreen = fullscreen;
2378 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2379 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2380 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2382 * There is no way to deactivate thread safety once it is enabled.
2384 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2387 /*For now just store the flag(needed in case of ddraw) */
2388 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2393 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2397 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2400 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2402 /* Resize the screen even without a window:
2403 * The app could have unset it with SetCooperativeLevel, but not called
2404 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2405 * but we don't have any hwnd
2408 memset(&devmode, 0, sizeof(devmode));
2409 devmode.dmSize = sizeof(devmode);
2410 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2411 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2412 devmode.dmPelsWidth = pMode->Width;
2413 devmode.dmPelsHeight = pMode->Height;
2415 devmode.dmDisplayFrequency = pMode->RefreshRate;
2416 if (pMode->RefreshRate != 0) {
2417 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2420 /* Only change the mode if necessary */
2421 if( (This->ddraw_width == pMode->Width) &&
2422 (This->ddraw_height == pMode->Height) &&
2423 (This->ddraw_format == pMode->Format) &&
2424 (pMode->RefreshRate == 0) ) {
2428 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2429 if (ret != DISP_CHANGE_SUCCESSFUL) {
2430 if(devmode.dmDisplayFrequency != 0) {
2431 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2432 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2433 devmode.dmDisplayFrequency = 0;
2434 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2436 if(ret != DISP_CHANGE_SUCCESSFUL) {
2437 return WINED3DERR_NOTAVAILABLE;
2441 /* Store the new values */
2442 This->ddraw_width = pMode->Width;
2443 This->ddraw_height = pMode->Height;
2444 This->ddraw_format = pMode->Format;
2446 /* Only do this with a window of course, and only if we're fullscreened */
2447 if(This->ddraw_window && This->ddraw_fullscreen)
2448 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2450 /* And finally clip mouse to our screen */
2451 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2452 ClipCursor(&clip_rc);
2457 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 *ppD3D= This->wineD3D;
2460 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2461 IWineD3D_AddRef(*ppD3D);
2465 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2469 (This->adapter->TextureRam/(1024*1024)),
2470 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2471 /* return simulated texture memory left */
2472 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 /* Update the current state block */
2484 This->updateStateBlock->changed.fvf = TRUE;
2486 if(This->updateStateBlock->fvf == fvf) {
2487 TRACE("Application is setting the old fvf over, nothing to do\n");
2491 This->updateStateBlock->fvf = fvf;
2492 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2498 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2501 *pfvf = This->stateBlock->fvf;
2506 * Get / Set Stream Source
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 IWineD3DVertexBuffer *oldSrc;
2512 if (StreamNumber >= MAX_STREAMS) {
2513 WARN("Stream out of range %d\n", StreamNumber);
2514 return WINED3DERR_INVALIDCALL;
2515 } else if(OffsetInBytes & 0x3) {
2516 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2517 return WINED3DERR_INVALIDCALL;
2520 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2521 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2523 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2525 if(oldSrc == pStreamData &&
2526 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2527 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2528 TRACE("Application is setting the old values over, nothing to do\n");
2532 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2534 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2535 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2538 /* Handle recording of state blocks */
2539 if (This->isRecordingState) {
2540 TRACE("Recording... not performing anything\n");
2541 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2542 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2546 /* Need to do a getParent and pass the references up */
2547 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2548 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2549 so for now, just count internally */
2550 if (pStreamData != NULL) {
2551 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2552 InterlockedIncrement(&vbImpl->bindCount);
2553 IWineD3DVertexBuffer_AddRef(pStreamData);
2555 if (oldSrc != NULL) {
2556 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2557 IWineD3DVertexBuffer_Release(oldSrc);
2560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2565 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2569 This->stateBlock->streamSource[StreamNumber],
2570 This->stateBlock->streamOffset[StreamNumber],
2571 This->stateBlock->streamStride[StreamNumber]);
2573 if (StreamNumber >= MAX_STREAMS) {
2574 WARN("Stream out of range %d\n", StreamNumber);
2575 return WINED3DERR_INVALIDCALL;
2577 *pStream = This->stateBlock->streamSource[StreamNumber];
2578 *pStride = This->stateBlock->streamStride[StreamNumber];
2580 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2583 if (*pStream != NULL) {
2584 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2589 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2592 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2594 /* Verify input at least in d3d9 this is invalid*/
2595 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2596 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2597 return WINED3DERR_INVALIDCALL;
2599 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2600 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2604 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2605 return WINED3DERR_INVALIDCALL;
2608 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2609 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2611 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2612 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2614 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2615 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2622 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2626 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2628 TRACE("(%p) : returning %d\n", This, *Divider);
2634 * Get / Set & Multiply Transform
2636 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 /* Most of this routine, comments included copied from ddraw tree initially: */
2640 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2642 /* Handle recording of state blocks */
2643 if (This->isRecordingState) {
2644 TRACE("Recording... not performing anything\n");
2645 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2646 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2651 * If the new matrix is the same as the current one,
2652 * we cut off any further processing. this seems to be a reasonable
2653 * optimization because as was noticed, some apps (warcraft3 for example)
2654 * tend towards setting the same matrix repeatedly for some reason.
2656 * From here on we assume that the new matrix is different, wherever it matters.
2658 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2659 TRACE("The app is setting the same matrix over again\n");
2662 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2666 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2667 where ViewMat = Camera space, WorldMat = world space.
2669 In OpenGL, camera and world space is combined into GL_MODELVIEW
2670 matrix. The Projection matrix stay projection matrix.
2673 /* Capture the times we can just ignore the change for now */
2674 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2675 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2676 /* Handled by the state manager */
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2685 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2686 *pMatrix = This->stateBlock->transforms[State];
2690 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2691 WINED3DMATRIX *mat = NULL;
2694 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2695 * below means it will be recorded in a state block change, but it
2696 * works regardless where it is recorded.
2697 * If this is found to be wrong, change to StateBlock.
2699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2700 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2702 if (State < HIGHEST_TRANSFORMSTATE)
2704 mat = &This->updateStateBlock->transforms[State];
2706 FIXME("Unhandled transform state!!\n");
2709 multiply_matrix(&temp, mat, pMatrix);
2711 /* Apply change via set transform - will reapply to eg. lights this way */
2712 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2718 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2719 you can reference any indexes you want as long as that number max are enabled at any
2720 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2721 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2722 but when recording, just build a chain pretty much of commands to be replayed. */
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2726 PLIGHTINFOEL *object = NULL;
2727 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2733 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2737 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2738 return WINED3DERR_INVALIDCALL;
2741 switch(pLight->Type) {
2742 case WINED3DLIGHT_POINT:
2743 case WINED3DLIGHT_SPOT:
2744 case WINED3DLIGHT_PARALLELPOINT:
2745 case WINED3DLIGHT_GLSPOT:
2746 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2749 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2750 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2751 return WINED3DERR_INVALIDCALL;
2755 case WINED3DLIGHT_DIRECTIONAL:
2756 /* Ignores attenuation */
2760 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2761 return WINED3DERR_INVALIDCALL;
2764 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2765 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2766 if(object->OriginalIndex == Index) break;
2771 TRACE("Adding new light\n");
2772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2774 ERR("Out of memory error when allocating a light\n");
2775 return E_OUTOFMEMORY;
2777 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2778 object->glIndex = -1;
2779 object->OriginalIndex = Index;
2780 object->changed = TRUE;
2783 /* Initialize the object */
2784 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,
2785 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2786 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2787 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2788 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2789 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2790 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2792 /* Save away the information */
2793 object->OriginalParms = *pLight;
2795 switch (pLight->Type) {
2796 case WINED3DLIGHT_POINT:
2798 object->lightPosn[0] = pLight->Position.x;
2799 object->lightPosn[1] = pLight->Position.y;
2800 object->lightPosn[2] = pLight->Position.z;
2801 object->lightPosn[3] = 1.0f;
2802 object->cutoff = 180.0f;
2806 case WINED3DLIGHT_DIRECTIONAL:
2808 object->lightPosn[0] = -pLight->Direction.x;
2809 object->lightPosn[1] = -pLight->Direction.y;
2810 object->lightPosn[2] = -pLight->Direction.z;
2811 object->lightPosn[3] = 0.0;
2812 object->exponent = 0.0f;
2813 object->cutoff = 180.0f;
2816 case WINED3DLIGHT_SPOT:
2818 object->lightPosn[0] = pLight->Position.x;
2819 object->lightPosn[1] = pLight->Position.y;
2820 object->lightPosn[2] = pLight->Position.z;
2821 object->lightPosn[3] = 1.0;
2824 object->lightDirn[0] = pLight->Direction.x;
2825 object->lightDirn[1] = pLight->Direction.y;
2826 object->lightDirn[2] = pLight->Direction.z;
2827 object->lightDirn[3] = 1.0;
2830 * opengl-ish and d3d-ish spot lights use too different models for the
2831 * light "intensity" as a function of the angle towards the main light direction,
2832 * so we only can approximate very roughly.
2833 * however spot lights are rather rarely used in games (if ever used at all).
2834 * furthermore if still used, probably nobody pays attention to such details.
2836 if (pLight->Falloff == 0) {
2837 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2838 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2839 * will always be 1.0 for both of them, and we don't have to care for the
2840 * rest of the rather complex calculation
2842 object->exponent = 0;
2844 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2845 if (rho < 0.0001) rho = 0.0001f;
2846 object->exponent = -0.3/log(cos(rho/2));
2848 if (object->exponent > 128.0) {
2849 object->exponent = 128.0;
2851 object->cutoff = pLight->Phi*90/M_PI;
2857 FIXME("Unrecognized light type %d\n", pLight->Type);
2860 /* Update the live definitions if the light is currently assigned a glIndex */
2861 if (object->glIndex != -1 && !This->isRecordingState) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2868 PLIGHTINFOEL *lightInfo = NULL;
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2872 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2874 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2875 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2876 if(lightInfo->OriginalIndex == Index) break;
2880 if (lightInfo == NULL) {
2881 TRACE("Light information requested but light not defined\n");
2882 return WINED3DERR_INVALIDCALL;
2885 *pLight = lightInfo->OriginalParms;
2890 * Get / Set Light Enable
2891 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2893 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2894 PLIGHTINFOEL *lightInfo = NULL;
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2898 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2900 /* Tests show true = 128...not clear why */
2901 Enable = Enable? 128: 0;
2903 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2904 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2905 if(lightInfo->OriginalIndex == Index) break;
2908 TRACE("Found light: %p\n", lightInfo);
2910 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2911 if (lightInfo == NULL) {
2913 TRACE("Light enabled requested but light not defined, so defining one!\n");
2914 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2916 /* Search for it again! Should be fairly quick as near head of list */
2917 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2918 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2919 if(lightInfo->OriginalIndex == Index) break;
2922 if (lightInfo == NULL) {
2923 FIXME("Adding default lights has failed dismally\n");
2924 return WINED3DERR_INVALIDCALL;
2928 lightInfo->enabledChanged = TRUE;
2930 if(lightInfo->glIndex != -1) {
2931 if(!This->isRecordingState) {
2932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2935 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2936 lightInfo->glIndex = -1;
2938 TRACE("Light already disabled, nothing to do\n");
2940 lightInfo->enabled = FALSE;
2942 lightInfo->enabled = TRUE;
2943 if (lightInfo->glIndex != -1) {
2945 TRACE("Nothing to do as light was enabled\n");
2948 /* Find a free gl light */
2949 for(i = 0; i < This->maxConcurrentLights; i++) {
2950 if(This->stateBlock->activeLights[i] == NULL) {
2951 This->stateBlock->activeLights[i] = lightInfo;
2952 lightInfo->glIndex = i;
2956 if(lightInfo->glIndex == -1) {
2957 /* Our tests show that Windows returns D3D_OK in this situation, even with
2958 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2959 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2960 * as well for those lights.
2962 * TODO: Test how this affects rendering
2964 FIXME("Too many concurrently active lights\n");
2968 /* i == lightInfo->glIndex */
2969 if(!This->isRecordingState) {
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2980 PLIGHTINFOEL *lightInfo = NULL;
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2984 TRACE("(%p) : for idx(%d)\n", This, Index);
2986 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2987 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2988 if(lightInfo->OriginalIndex == Index) break;
2992 if (lightInfo == NULL) {
2993 TRACE("Light enabled state requested but light not defined\n");
2994 return WINED3DERR_INVALIDCALL;
2996 /* true is 128 according to SetLightEnable */
2997 *pEnable = lightInfo->enabled ? 128 : 0;
3002 * Get / Set Clip Planes
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3006 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3008 /* Validate Index */
3009 if (Index >= GL_LIMITS(clipplanes)) {
3010 TRACE("Application has requested clipplane this device doesn't support\n");
3011 return WINED3DERR_INVALIDCALL;
3014 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3016 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3017 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3018 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3019 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3020 TRACE("Application is setting old values over, nothing to do\n");
3024 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3025 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3026 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3027 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3029 /* Handle recording of state blocks */
3030 if (This->isRecordingState) {
3031 TRACE("Recording... not performing anything\n");
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : for idx %d\n", This, Index);
3044 /* Validate Index */
3045 if (Index >= GL_LIMITS(clipplanes)) {
3046 TRACE("Application has requested clipplane this device doesn't support\n");
3047 return WINED3DERR_INVALIDCALL;
3050 pPlane[0] = This->stateBlock->clipplane[Index][0];
3051 pPlane[1] = This->stateBlock->clipplane[Index][1];
3052 pPlane[2] = This->stateBlock->clipplane[Index][2];
3053 pPlane[3] = This->stateBlock->clipplane[Index][3];
3058 * Get / Set Clip Plane Status
3059 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 FIXME("(%p) : stub\n", This);
3064 if (NULL == pClipStatus) {
3065 return WINED3DERR_INVALIDCALL;
3067 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3068 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 FIXME("(%p) : stub\n", This);
3075 if (NULL == pClipStatus) {
3076 return WINED3DERR_INVALIDCALL;
3078 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3079 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3084 * Get / Set Material
3086 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3091 This->updateStateBlock->changed.material = TRUE;
3092 This->updateStateBlock->material = *pMaterial;
3094 /* Handle recording of state blocks */
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3104 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3106 *pMaterial = This->updateStateBlock->material;
3107 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3108 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3109 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3110 pMaterial->Ambient.b, pMaterial->Ambient.a);
3111 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3112 pMaterial->Specular.b, pMaterial->Specular.a);
3113 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3114 pMaterial->Emissive.b, pMaterial->Emissive.a);
3115 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3123 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 IWineD3DIndexBuffer *oldIdxs;
3127 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3128 oldIdxs = This->updateStateBlock->pIndexData;
3130 This->updateStateBlock->changed.indices = TRUE;
3131 This->updateStateBlock->pIndexData = pIndexData;
3133 /* Handle recording of state blocks */
3134 if (This->isRecordingState) {
3135 TRACE("Recording... not performing anything\n");
3136 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3137 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3141 if(oldIdxs != pIndexData) {
3142 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3143 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3144 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3149 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3152 *ppIndexData = This->stateBlock->pIndexData;
3154 /* up ref count on ppindexdata */
3156 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3157 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3159 TRACE("(%p) No index data set\n", This);
3161 TRACE("Returning %p\n", *ppIndexData);
3166 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3167 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 TRACE("(%p)->(%d)\n", This, BaseIndex);
3171 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3172 TRACE("Application is setting the old value over, nothing to do\n");
3176 This->updateStateBlock->baseVertexIndex = BaseIndex;
3178 if (This->isRecordingState) {
3179 TRACE("Recording... not performing anything\n");
3182 /* The base vertex index affects the stream sources */
3183 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3187 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3188 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3189 TRACE("(%p) : base_index %p\n", This, base_index);
3191 *base_index = This->stateBlock->baseVertexIndex;
3193 TRACE("Returning %u\n", *base_index);
3199 * Get / Set Viewports
3201 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3204 TRACE("(%p)\n", This);
3205 This->updateStateBlock->changed.viewport = TRUE;
3206 This->updateStateBlock->viewport = *pViewport;
3208 /* Handle recording of state blocks */
3209 if (This->isRecordingState) {
3210 TRACE("Recording... not performing anything\n");
3214 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3215 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3217 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3224 TRACE("(%p)\n", This);
3225 *pViewport = This->stateBlock->viewport;
3230 * Get / Set Render States
3231 * TODO: Verify against dx9 definitions
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 DWORD oldValue = This->stateBlock->renderState[State];
3238 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3240 This->updateStateBlock->changed.renderState[State] = TRUE;
3241 This->updateStateBlock->renderState[State] = Value;
3243 /* Handle recording of state blocks */
3244 if (This->isRecordingState) {
3245 TRACE("Recording... not performing anything\n");
3249 /* Compared here and not before the assignment to allow proper stateblock recording */
3250 if(Value == oldValue) {
3251 TRACE("Application is setting the old value over, nothing to do\n");
3253 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3259 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3261 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3262 *pValue = This->stateBlock->renderState[State];
3267 * Get / Set Sampler States
3268 * TODO: Verify against dx9 definitions
3271 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3276 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3278 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3279 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3282 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3283 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3284 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3287 * SetSampler is designed to allow for more than the standard up to 8 textures
3288 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3289 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3291 * http://developer.nvidia.com/object/General_FAQ.html#t6
3293 * There are two new settings for GForce
3295 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3296 * and the texture one:
3297 * GL_MAX_TEXTURE_COORDS_ARB.
3298 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3301 oldValue = This->stateBlock->samplerState[Sampler][Type];
3302 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3303 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3305 /* Handle recording of state blocks */
3306 if (This->isRecordingState) {
3307 TRACE("Recording... not performing anything\n");
3311 if(oldValue == Value) {
3312 TRACE("Application is setting the old value over, nothing to do\n");
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3321 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3325 This, Sampler, debug_d3dsamplerstate(Type), Type);
3327 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3328 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3331 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3332 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3333 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3335 *Value = This->stateBlock->samplerState[Sampler][Type];
3336 TRACE("(%p) : Returning %#x\n", This, *Value);
3341 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3344 This->updateStateBlock->changed.scissorRect = TRUE;
3345 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3346 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3349 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3351 if(This->isRecordingState) {
3352 TRACE("Recording... not performing anything\n");
3356 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3361 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3362 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3364 *pRect = This->updateStateBlock->scissorRect;
3365 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3369 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3371 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3373 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3375 This->updateStateBlock->vertexDecl = pDecl;
3376 This->updateStateBlock->changed.vertexDecl = TRUE;
3378 if (This->isRecordingState) {
3379 TRACE("Recording... not performing anything\n");
3381 } else if(pDecl == oldDecl) {
3382 /* Checked after the assignment to allow proper stateblock recording */
3383 TRACE("Application is setting the old declaration over, nothing to do\n");
3387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3391 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3394 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3396 *ppDecl = This->stateBlock->vertexDecl;
3397 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3401 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3405 This->updateStateBlock->vertexShader = pShader;
3406 This->updateStateBlock->changed.vertexShader = TRUE;
3408 if (This->isRecordingState) {
3409 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3410 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3411 TRACE("Recording... not performing anything\n");
3413 } else if(oldShader == pShader) {
3414 /* Checked here to allow proper stateblock recording */
3415 TRACE("App is setting the old shader over, nothing to do\n");
3419 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3420 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3421 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3423 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3428 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3431 if (NULL == ppShader) {
3432 return WINED3DERR_INVALIDCALL;
3434 *ppShader = This->stateBlock->vertexShader;
3435 if( NULL != *ppShader)
3436 IWineD3DVertexShader_AddRef(*ppShader);
3438 TRACE("(%p) : returning %p\n", This, *ppShader);
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3443 IWineD3DDevice *iface,
3445 CONST BOOL *srcData,
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3449 int i, cnt = min(count, MAX_CONST_B - start);
3451 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3452 iface, srcData, start, count);
3454 if (srcData == NULL || cnt < 0)
3455 return WINED3DERR_INVALIDCALL;
3457 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3458 for (i = 0; i < cnt; i++)
3459 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3461 for (i = start; i < cnt + start; ++i) {
3462 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3465 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3470 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3471 IWineD3DDevice *iface,
3476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3477 int cnt = min(count, MAX_CONST_B - start);
3479 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3480 iface, dstData, start, count);
3482 if (dstData == NULL || cnt < 0)
3483 return WINED3DERR_INVALIDCALL;
3485 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3489 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3490 IWineD3DDevice *iface,
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int i, cnt = min(count, MAX_CONST_I - start);
3498 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3499 iface, srcData, start, count);
3501 if (srcData == NULL || cnt < 0)
3502 return WINED3DERR_INVALIDCALL;
3504 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3505 for (i = 0; i < cnt; i++)
3506 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3507 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3509 for (i = start; i < cnt + start; ++i) {
3510 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3513 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3518 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3519 IWineD3DDevice *iface,
3524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3525 int cnt = min(count, MAX_CONST_I - start);
3527 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3528 iface, dstData, start, count);
3530 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3531 return WINED3DERR_INVALIDCALL;
3533 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3537 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3538 IWineD3DDevice *iface,
3540 CONST float *srcData,
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3546 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3547 iface, srcData, start, count);
3549 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3550 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3555 for (i = 0; i < count; i++)
3556 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3557 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3560 for (i = start; i < count + start; ++i) {
3561 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3562 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3563 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3564 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3565 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3567 ptr->idx[ptr->count++] = i;
3568 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3577 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3578 IWineD3DDevice *iface,
3580 CONST float *srcData,
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3586 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3587 iface, srcData, start, count);
3589 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3590 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3591 return WINED3DERR_INVALIDCALL;
3593 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3595 for (i = 0; i < count; i++)
3596 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3597 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3600 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3601 * context. On a context switch the old context will be fully dirtified
3603 memset(This->activeContext->vshader_const_dirty + start, 1,
3604 sizeof(*This->activeContext->vshader_const_dirty) * count);
3605 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3607 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3612 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3613 IWineD3DDevice *iface,
3618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3619 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3621 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3622 iface, dstData, start, count);
3624 if (dstData == NULL || cnt < 0)
3625 return WINED3DERR_INVALIDCALL;
3627 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3631 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3633 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3634 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3638 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3639 int i = This->rev_tex_unit_map[unit];
3640 int j = This->texUnitMap[stage];
3642 This->texUnitMap[stage] = unit;
3643 if (i != -1 && i != stage) {
3644 This->texUnitMap[i] = -1;
3647 This->rev_tex_unit_map[unit] = stage;
3648 if (j != -1 && j != unit) {
3649 This->rev_tex_unit_map[j] = -1;
3653 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3656 for (i = 0; i < MAX_TEXTURES; ++i) {
3657 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3658 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3659 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3660 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3661 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3662 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3663 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3664 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3666 if (color_op == WINED3DTOP_DISABLE) {
3667 /* Not used, and disable higher stages */
3668 while (i < MAX_TEXTURES) {
3669 This->fixed_function_usage_map[i] = FALSE;
3675 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3676 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3677 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3678 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3679 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3680 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3681 This->fixed_function_usage_map[i] = TRUE;
3683 This->fixed_function_usage_map[i] = FALSE;
3686 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3687 This->fixed_function_usage_map[i+1] = TRUE;
3692 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3695 device_update_fixed_function_usage_map(This);
3697 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3698 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3699 if (!This->fixed_function_usage_map[i]) continue;
3701 if (This->texUnitMap[i] != i) {
3702 device_map_stage(This, i, i);
3703 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3704 markTextureStagesDirty(This, i);
3710 /* Now work out the mapping */
3712 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3713 if (!This->fixed_function_usage_map[i]) continue;
3715 if (This->texUnitMap[i] != tex) {
3716 device_map_stage(This, i, tex);
3717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3718 markTextureStagesDirty(This, i);
3725 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3726 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3729 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3730 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3731 device_map_stage(This, i, i);
3732 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3733 if (i < MAX_TEXTURES) {
3734 markTextureStagesDirty(This, i);
3740 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3741 int current_mapping = This->rev_tex_unit_map[unit];
3743 if (current_mapping == -1) {
3744 /* Not currently used */
3748 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3749 /* Used by a fragment sampler */
3751 if (!pshader_sampler_tokens) {
3752 /* No pixel shader, check fixed function */
3753 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3756 /* Pixel shader, check the shader's sampler map */
3757 return !pshader_sampler_tokens[current_mapping];
3760 /* Used by a vertex sampler */
3761 return !vshader_sampler_tokens[current_mapping];
3764 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3765 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3766 DWORD *pshader_sampler_tokens = NULL;
3767 int start = GL_LIMITS(combined_samplers) - 1;
3771 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3773 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3774 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3775 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3778 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3779 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3780 if (vshader_sampler_tokens[i]) {
3781 if (This->texUnitMap[vsampler_idx] != -1) {
3782 /* Already mapped somewhere */
3786 while (start >= 0) {
3787 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3788 device_map_stage(This, vsampler_idx, start);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3801 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3802 BOOL vs = use_vs(This);
3803 BOOL ps = use_ps(This);
3806 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3807 * that would be really messy and require shader recompilation
3808 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3809 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3812 device_map_psamplers(This);
3814 device_map_fixed_function_samplers(This);
3818 device_map_vsamplers(This, ps);
3822 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3824 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3825 This->updateStateBlock->pixelShader = pShader;
3826 This->updateStateBlock->changed.pixelShader = TRUE;
3828 /* Handle recording of state blocks */
3829 if (This->isRecordingState) {
3830 TRACE("Recording... not performing anything\n");
3833 if (This->isRecordingState) {
3834 TRACE("Recording... not performing anything\n");
3835 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3836 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3840 if(pShader == oldShader) {
3841 TRACE("App is setting the old pixel shader over, nothing to do\n");
3845 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3846 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3848 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3854 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3857 if (NULL == ppShader) {
3858 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3859 return WINED3DERR_INVALIDCALL;
3862 *ppShader = This->stateBlock->pixelShader;
3863 if (NULL != *ppShader) {
3864 IWineD3DPixelShader_AddRef(*ppShader);
3866 TRACE("(%p) : returning %p\n", This, *ppShader);
3870 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3871 IWineD3DDevice *iface,
3873 CONST BOOL *srcData,
3876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3877 int i, cnt = min(count, MAX_CONST_B - start);
3879 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3880 iface, srcData, start, count);
3882 if (srcData == NULL || cnt < 0)
3883 return WINED3DERR_INVALIDCALL;
3885 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3886 for (i = 0; i < cnt; i++)
3887 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3889 for (i = start; i < cnt + start; ++i) {
3890 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3893 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3898 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3899 IWineD3DDevice *iface,
3904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3905 int cnt = min(count, MAX_CONST_B - start);
3907 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3908 iface, dstData, start, count);
3910 if (dstData == NULL || cnt < 0)
3911 return WINED3DERR_INVALIDCALL;
3913 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3917 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3918 IWineD3DDevice *iface,
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 int i, cnt = min(count, MAX_CONST_I - start);
3926 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3927 iface, srcData, start, count);
3929 if (srcData == NULL || cnt < 0)
3930 return WINED3DERR_INVALIDCALL;
3932 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3933 for (i = 0; i < cnt; i++)
3934 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3935 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3937 for (i = start; i < cnt + start; ++i) {
3938 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3946 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3947 IWineD3DDevice *iface,
3952 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3953 int cnt = min(count, MAX_CONST_I - start);
3955 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3956 iface, dstData, start, count);
3958 if (dstData == NULL || cnt < 0)
3959 return WINED3DERR_INVALIDCALL;
3961 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3965 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3966 IWineD3DDevice *iface,
3968 CONST float *srcData,
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3974 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3975 iface, srcData, start, count);
3977 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3978 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3983 for (i = 0; i < count; i++)
3984 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3985 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3988 for (i = start; i < count + start; ++i) {
3989 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3990 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3991 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3992 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3993 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3995 ptr->idx[ptr->count++] = i;
3996 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4005 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4006 IWineD3DDevice *iface,
4008 CONST float *srcData,
4011 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4014 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4015 iface, srcData, start, count);
4017 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4018 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4019 return WINED3DERR_INVALIDCALL;
4021 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4023 for (i = 0; i < count; i++)
4024 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4025 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4028 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4029 * context. On a context switch the old context will be fully dirtified
4031 memset(This->activeContext->pshader_const_dirty + start, 1,
4032 sizeof(*This->activeContext->pshader_const_dirty) * count);
4033 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4040 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4041 IWineD3DDevice *iface,
4046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4047 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4049 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4050 iface, dstData, start, count);
4052 if (dstData == NULL || cnt < 0)
4053 return WINED3DERR_INVALIDCALL;
4055 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4059 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4061 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4062 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4064 DWORD DestFVF = dest->fvf;
4066 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4070 if (lpStrideData->u.s.normal.lpData) {
4071 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4074 if (lpStrideData->u.s.position.lpData == NULL) {
4075 ERR("Source has no position mask\n");
4076 return WINED3DERR_INVALIDCALL;
4079 /* We might access VBOs from this code, so hold the lock */
4082 if (dest->resource.allocatedMemory == NULL) {
4083 /* This may happen if we do direct locking into a vbo. Unlikely,
4084 * but theoretically possible(ddraw processvertices test)
4086 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4087 if(!dest->resource.allocatedMemory) {
4089 ERR("Out of memory\n");
4090 return E_OUTOFMEMORY;
4094 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4095 checkGLcall("glBindBufferARB");
4096 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4098 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4100 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4101 checkGLcall("glUnmapBufferARB");
4105 /* Get a pointer into the destination vbo(create one if none exists) and
4106 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4108 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4109 dest->Flags |= VBFLAG_CREATEVBO;
4110 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4114 unsigned char extrabytes = 0;
4115 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4116 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4117 * this may write 4 extra bytes beyond the area that should be written
4119 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4120 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4121 if(!dest_conv_addr) {
4122 ERR("Out of memory\n");
4123 /* Continue without storing converted vertices */
4125 dest_conv = dest_conv_addr;
4129 * a) WINED3DRS_CLIPPING is enabled
4130 * b) WINED3DVOP_CLIP is passed
4132 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4133 static BOOL warned = FALSE;
4135 * The clipping code is not quite correct. Some things need
4136 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4137 * so disable clipping for now.
4138 * (The graphics in Half-Life are broken, and my processvertices
4139 * test crashes with IDirect3DDevice3)
4145 FIXME("Clipping is broken and disabled for now\n");
4147 } else doClip = FALSE;
4148 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4150 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4153 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4154 WINED3DTS_PROJECTION,
4156 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4157 WINED3DTS_WORLDMATRIX(0),
4160 TRACE("View mat:\n");
4161 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);
4162 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);
4163 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);
4164 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);
4166 TRACE("Proj mat:\n");
4167 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);
4168 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);
4169 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);
4170 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);
4172 TRACE("World mat:\n");
4173 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);
4174 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);
4175 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);
4176 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);
4178 /* Get the viewport */
4179 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4180 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4181 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4183 multiply_matrix(&mat,&view_mat,&world_mat);
4184 multiply_matrix(&mat,&proj_mat,&mat);
4186 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4188 for (i = 0; i < dwCount; i+= 1) {
4189 unsigned int tex_index;
4191 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4192 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4193 /* The position first */
4195 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4197 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4199 /* Multiplication with world, view and projection matrix */
4200 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);
4201 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);
4202 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);
4203 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);
4205 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4207 /* WARNING: The following things are taken from d3d7 and were not yet checked
4208 * against d3d8 or d3d9!
4211 /* Clipping conditions: From msdn
4213 * A vertex is clipped if it does not match the following requirements
4217 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4219 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4220 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4225 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4226 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4229 /* "Normal" viewport transformation (not clipped)
4230 * 1) The values are divided by rhw
4231 * 2) The y axis is negative, so multiply it with -1
4232 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4233 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4234 * 4) Multiply x with Width/2 and add Width/2
4235 * 5) The same for the height
4236 * 6) Add the viewpoint X and Y to the 2D coordinates and
4237 * The minimum Z value to z
4238 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4240 * Well, basically it's simply a linear transformation into viewport
4252 z *= vp.MaxZ - vp.MinZ;
4254 x += vp.Width / 2 + vp.X;
4255 y += vp.Height / 2 + vp.Y;
4260 /* That vertex got clipped
4261 * Contrary to OpenGL it is not dropped completely, it just
4262 * undergoes a different calculation.
4264 TRACE("Vertex got clipped\n");
4271 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4272 * outside of the main vertex buffer memory. That needs some more
4277 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4280 ( (float *) dest_ptr)[0] = x;
4281 ( (float *) dest_ptr)[1] = y;
4282 ( (float *) dest_ptr)[2] = z;
4283 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4285 dest_ptr += 3 * sizeof(float);
4287 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4288 dest_ptr += sizeof(float);
4293 ( (float *) dest_conv)[0] = x * w;
4294 ( (float *) dest_conv)[1] = y * w;
4295 ( (float *) dest_conv)[2] = z * w;
4296 ( (float *) dest_conv)[3] = w;
4298 dest_conv += 3 * sizeof(float);
4300 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4301 dest_conv += sizeof(float);
4305 if (DestFVF & WINED3DFVF_PSIZE) {
4306 dest_ptr += sizeof(DWORD);
4307 if(dest_conv) dest_conv += sizeof(DWORD);
4309 if (DestFVF & WINED3DFVF_NORMAL) {
4311 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4312 /* AFAIK this should go into the lighting information */
4313 FIXME("Didn't expect the destination to have a normal\n");
4314 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4316 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4320 if (DestFVF & WINED3DFVF_DIFFUSE) {
4322 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4324 static BOOL warned = FALSE;
4327 ERR("No diffuse color in source, but destination has one\n");
4331 *( (DWORD *) dest_ptr) = 0xffffffff;
4332 dest_ptr += sizeof(DWORD);
4335 *( (DWORD *) dest_conv) = 0xffffffff;
4336 dest_conv += sizeof(DWORD);
4340 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4342 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4343 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4344 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4345 dest_conv += sizeof(DWORD);
4350 if (DestFVF & WINED3DFVF_SPECULAR) {
4351 /* What's the color value in the feedback buffer? */
4353 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4355 static BOOL warned = FALSE;
4358 ERR("No specular color in source, but destination has one\n");
4362 *( (DWORD *) dest_ptr) = 0xFF000000;
4363 dest_ptr += sizeof(DWORD);
4366 *( (DWORD *) dest_conv) = 0xFF000000;
4367 dest_conv += sizeof(DWORD);
4371 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4373 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4374 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4375 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4376 dest_conv += sizeof(DWORD);
4381 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4383 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4384 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4386 ERR("No source texture, but destination requests one\n");
4387 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4388 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4391 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4393 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4400 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4401 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4402 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4403 dwCount * get_flexible_vertex_size(DestFVF),
4405 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4406 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4413 #undef copy_and_next
4415 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4416 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4417 WineDirect3DVertexStridedData strided;
4418 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4419 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4422 ERR("Output vertex declaration not implemented yet\n");
4425 /* Need any context to write to the vbo. */
4426 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4428 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4429 * control the streamIsUP flag, thus restore it afterwards.
4431 This->stateBlock->streamIsUP = FALSE;
4432 memset(&strided, 0, sizeof(strided));
4433 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4434 This->stateBlock->streamIsUP = streamWasUP;
4436 if(vbo || SrcStartIndex) {
4438 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4439 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4441 * Also get the start index in, but only loop over all elements if there's something to add at all.
4443 #define FIXSRC(type) \
4444 if(strided.u.s.type.VBO) { \
4445 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4446 strided.u.s.type.VBO = 0; \
4447 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4449 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4453 if(strided.u.s.type.lpData) { \
4454 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4457 FIXSRC(blendWeights);
4458 FIXSRC(blendMatrixIndices);
4463 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4464 FIXSRC(texCoords[i]);
4477 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4481 * Get / Set Texture Stage States
4482 * TODO: Verify against dx9 definitions
4484 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4488 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4490 if (Stage >= MAX_TEXTURES) {
4491 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4495 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4496 This->updateStateBlock->textureState[Stage][Type] = Value;
4498 if (This->isRecordingState) {
4499 TRACE("Recording... not performing anything\n");
4503 /* Checked after the assignments to allow proper stateblock recording */
4504 if(oldValue == Value) {
4505 TRACE("App is setting the old value over, nothing to do\n");
4509 if(Stage > This->stateBlock->lowest_disabled_stage &&
4510 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4511 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4512 * Changes in other states are important on disabled stages too
4517 if(Type == WINED3DTSS_COLOROP) {
4520 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4521 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4522 * they have to be disabled
4524 * The current stage is dirtified below.
4526 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4527 TRACE("Additionally dirtifying stage %d\n", i);
4528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4530 This->stateBlock->lowest_disabled_stage = Stage;
4531 TRACE("New lowest disabled: %d\n", Stage);
4532 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4533 /* Previously disabled stage enabled. Stages above it may need enabling
4534 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4535 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4537 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4540 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4541 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4544 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4545 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4547 This->stateBlock->lowest_disabled_stage = i;
4548 TRACE("New lowest disabled: %d\n", i);
4550 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4551 /* TODO: Built a stage -> texture unit mapping for register combiners */
4555 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4560 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4561 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4562 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4563 *pValue = This->updateStateBlock->textureState[Stage][Type];
4570 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 IWineD3DBaseTexture *oldTexture;
4574 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4576 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4577 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4580 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4581 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4582 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4585 oldTexture = This->updateStateBlock->textures[Stage];
4587 if(pTexture != NULL) {
4588 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4590 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4591 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4592 return WINED3DERR_INVALIDCALL;
4594 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4597 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4598 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4600 This->updateStateBlock->changed.textures[Stage] = TRUE;
4601 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4602 This->updateStateBlock->textures[Stage] = pTexture;
4604 /* Handle recording of state blocks */
4605 if (This->isRecordingState) {
4606 TRACE("Recording... not performing anything\n");
4610 if(oldTexture == pTexture) {
4611 TRACE("App is setting the same texture again, nothing to do\n");
4615 /** NOTE: MSDN says that setTexture increases the reference count,
4616 * and that the application must set the texture back to null (or have a leaky application),
4617 * This means we should pass the refcount up to the parent
4618 *******************************/
4619 if (NULL != This->updateStateBlock->textures[Stage]) {
4620 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4621 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4623 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4624 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4625 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4626 * so the COLOROP and ALPHAOP have to be dirtified.
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4629 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4631 if(bindCount == 1) {
4632 new->baseTexture.sampler = Stage;
4634 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4638 if (NULL != oldTexture) {
4639 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4640 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4642 IWineD3DBaseTexture_Release(oldTexture);
4643 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4644 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4648 if(bindCount && old->baseTexture.sampler == Stage) {
4650 /* Have to do a search for the other sampler(s) where the texture is bound to
4651 * Shouldn't happen as long as apps bind a texture only to one stage
4653 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4654 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4655 if(This->updateStateBlock->textures[i] == oldTexture) {
4656 old->baseTexture.sampler = i;
4663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4668 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4671 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4673 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4674 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4677 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4678 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4679 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4682 *ppTexture=This->stateBlock->textures[Stage];
4684 IWineD3DBaseTexture_AddRef(*ppTexture);
4686 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4694 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4695 IWineD3DSurface **ppBackBuffer) {
4696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4697 IWineD3DSwapChain *swapChain;
4700 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4702 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4703 if (hr == WINED3D_OK) {
4704 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4705 IWineD3DSwapChain_Release(swapChain);
4707 *ppBackBuffer = NULL;
4712 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 WARN("(%p) : stub, calling idirect3d for now\n", This);
4715 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4718 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4719 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4720 IWineD3DSwapChain *swapChain;
4723 if(iSwapChain > 0) {
4724 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4725 if (hr == WINED3D_OK) {
4726 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4727 IWineD3DSwapChain_Release(swapChain);
4729 FIXME("(%p) Error getting display mode\n", This);
4732 /* Don't read the real display mode,
4733 but return the stored mode instead. X11 can't change the color
4734 depth, and some apps are pretty angry if they SetDisplayMode from
4735 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4737 Also don't relay to the swapchain because with ddraw it's possible
4738 that there isn't a swapchain at all */
4739 pMode->Width = This->ddraw_width;
4740 pMode->Height = This->ddraw_height;
4741 pMode->Format = This->ddraw_format;
4742 pMode->RefreshRate = 0;
4749 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 TRACE("(%p)->(%p)\n", This, hWnd);
4753 if(This->ddraw_fullscreen) {
4754 if(This->ddraw_window && This->ddraw_window != hWnd) {
4755 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4757 if(hWnd && This->ddraw_window != hWnd) {
4758 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4762 This->ddraw_window = hWnd;
4766 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 TRACE("(%p)->(%p)\n", This, hWnd);
4770 *hWnd = This->ddraw_window;
4775 * Stateblock related functions
4778 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4779 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4780 IWineD3DStateBlockImpl *object;
4781 HRESULT temp_result;
4784 TRACE("(%p)\n", This);
4786 if (This->isRecordingState) {
4787 return WINED3DERR_INVALIDCALL;
4790 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4791 if (NULL == object ) {
4792 FIXME("(%p)Error allocating memory for stateblock\n", This);
4793 return E_OUTOFMEMORY;
4795 TRACE("(%p) created object %p\n", This, object);
4796 object->wineD3DDevice= This;
4797 /** FIXME: object->parent = parent; **/
4798 object->parent = NULL;
4799 object->blockType = WINED3DSBT_RECORDED;
4801 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4803 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4804 list_init(&object->lightMap[i]);
4807 temp_result = allocate_shader_constants(object);
4808 if (WINED3D_OK != temp_result)
4811 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4812 This->updateStateBlock = object;
4813 This->isRecordingState = TRUE;
4815 TRACE("(%p) recording stateblock %p\n",This , object);
4819 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4822 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4824 if (!This->isRecordingState) {
4825 FIXME("(%p) not recording! returning error\n", This);
4826 *ppStateBlock = NULL;
4827 return WINED3DERR_INVALIDCALL;
4830 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4831 if(object->changed.renderState[i]) {
4832 object->contained_render_states[object->num_contained_render_states] = i;
4833 object->num_contained_render_states++;
4836 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4837 if(object->changed.transform[i]) {
4838 object->contained_transform_states[object->num_contained_transform_states] = i;
4839 object->num_contained_transform_states++;
4842 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4843 if(object->changed.vertexShaderConstantsF[i]) {
4844 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4845 object->num_contained_vs_consts_f++;
4848 for(i = 0; i < MAX_CONST_I; i++) {
4849 if(object->changed.vertexShaderConstantsI[i]) {
4850 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4851 object->num_contained_vs_consts_i++;
4854 for(i = 0; i < MAX_CONST_B; i++) {
4855 if(object->changed.vertexShaderConstantsB[i]) {
4856 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4857 object->num_contained_vs_consts_b++;
4860 for(i = 0; i < MAX_CONST_I; i++) {
4861 if(object->changed.pixelShaderConstantsI[i]) {
4862 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4863 object->num_contained_ps_consts_i++;
4866 for(i = 0; i < MAX_CONST_B; i++) {
4867 if(object->changed.pixelShaderConstantsB[i]) {
4868 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4869 object->num_contained_ps_consts_b++;
4872 for(i = 0; i < MAX_TEXTURES; i++) {
4873 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4874 if(object->changed.textureState[i][j]) {
4875 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4876 object->contained_tss_states[object->num_contained_tss_states].state = j;
4877 object->num_contained_tss_states++;
4881 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4882 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4883 if(object->changed.samplerState[i][j]) {
4884 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4885 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4886 object->num_contained_sampler_states++;
4891 *ppStateBlock = (IWineD3DStateBlock*) object;
4892 This->isRecordingState = FALSE;
4893 This->updateStateBlock = This->stateBlock;
4894 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4895 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4896 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4901 * Scene related functions
4903 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4904 /* At the moment we have no need for any functionality at the beginning
4906 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4907 TRACE("(%p)\n", This);
4910 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4911 return WINED3DERR_INVALIDCALL;
4913 This->inScene = TRUE;
4917 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4918 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4919 TRACE("(%p)\n", This);
4921 if(!This->inScene) {
4922 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4923 return WINED3DERR_INVALIDCALL;
4926 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4927 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4930 checkGLcall("glFlush");
4933 This->inScene = FALSE;
4937 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4938 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4939 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4940 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4941 IWineD3DSwapChain *swapChain = NULL;
4943 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4945 TRACE("(%p) Presenting the frame\n", This);
4947 for(i = 0 ; i < swapchains ; i ++) {
4949 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4950 TRACE("presentinng chain %d, %p\n", i, swapChain);
4951 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4952 IWineD3DSwapChain_Release(swapChain);
4958 /* Not called from the VTable (internal subroutine) */
4959 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4960 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4961 float Z, DWORD Stencil) {
4962 GLbitfield glMask = 0;
4964 WINED3DRECT curRect;
4966 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4967 UINT drawable_width, drawable_height;
4968 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4970 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4971 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4972 * for the cleared parts, and the untouched parts.
4974 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4975 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4976 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4977 * checking all this if the dest surface is in the drawable anyway.
4979 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4981 if(vp->X != 0 || vp->Y != 0 ||
4982 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4983 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4986 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4987 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4988 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4989 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4990 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4993 if(Count > 0 && pRects && (
4994 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4995 pRects[0].x2 < target->currentDesc.Width ||
4996 pRects[0].y2 < target->currentDesc.Height)) {
4997 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5004 target->get_drawable_size(target, &drawable_width, &drawable_height);
5006 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5009 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5010 apply_fbo_state((IWineD3DDevice *) This);
5013 /* Only set the values up once, as they are not changing */
5014 if (Flags & WINED3DCLEAR_STENCIL) {
5015 glClearStencil(Stencil);
5016 checkGLcall("glClearStencil");
5017 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5018 glStencilMask(0xFFFFFFFF);
5021 if (Flags & WINED3DCLEAR_ZBUFFER) {
5022 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5023 glDepthMask(GL_TRUE);
5025 checkGLcall("glClearDepth");
5026 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5029 if (vp->X != 0 || vp->Y != 0 ||
5030 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5031 surface_load_ds_location(This->stencilBufferTarget, location);
5033 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5034 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5035 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5036 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5037 surface_load_ds_location(This->stencilBufferTarget, location);
5039 else if (Count > 0 && pRects && (
5040 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5041 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5042 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5043 surface_load_ds_location(This->stencilBufferTarget, location);
5047 if (Flags & WINED3DCLEAR_TARGET) {
5048 TRACE("Clearing screen with glClear to color %x\n", Color);
5049 glClearColor(D3DCOLOR_R(Color),
5053 checkGLcall("glClearColor");
5055 /* Clear ALL colors! */
5056 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5057 glMask = glMask | GL_COLOR_BUFFER_BIT;
5060 vp_rect.left = vp->X;
5061 vp_rect.top = vp->Y;
5062 vp_rect.right = vp->X + vp->Width;
5063 vp_rect.bottom = vp->Y + vp->Height;
5064 if (!(Count > 0 && pRects)) {
5065 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5066 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5068 if(This->render_offscreen) {
5069 glScissor(vp_rect.left, vp_rect.top,
5070 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5072 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5073 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5075 checkGLcall("glScissor");
5077 checkGLcall("glClear");
5079 /* Now process each rect in turn */
5080 for (i = 0; i < Count; i++) {
5081 /* Note gl uses lower left, width/height */
5082 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5083 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5084 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5086 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5087 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5088 curRect.x1, (target->currentDesc.Height - curRect.y2),
5089 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5091 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5092 * The rectangle is not cleared, no error is returned, but further rectanlges are
5093 * still cleared if they are valid
5095 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5096 TRACE("Rectangle with negative dimensions, ignoring\n");
5100 if(This->render_offscreen) {
5101 glScissor(curRect.x1, curRect.y1,
5102 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5104 glScissor(curRect.x1, drawable_height - curRect.y2,
5105 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5107 checkGLcall("glScissor");
5110 checkGLcall("glClear");
5114 /* Restore the old values (why..?) */
5115 if (Flags & WINED3DCLEAR_STENCIL) {
5116 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5118 if (Flags & WINED3DCLEAR_TARGET) {
5119 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5120 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5121 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5122 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5123 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5125 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5126 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5128 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5129 /* TODO: Move the fbo logic into ModifyLocation() */
5130 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5131 target->Flags |= SFLAG_INTEXTURE;
5134 if (Flags & WINED3DCLEAR_ZBUFFER) {
5135 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5136 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5137 surface_modify_ds_location(This->stencilBufferTarget, location);
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 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 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);
6169 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6170 checkGLcall("glFramebufferRenderbufferEXT");
6174 glEnable(GL_SCISSOR_TEST);
6176 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6178 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6179 rect->x2 - rect->x1, rect->y2 - rect->y1);
6181 checkGLcall("glScissor");
6183 glDisable(GL_SCISSOR_TEST);
6185 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6187 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6188 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6190 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6191 glClear(GL_COLOR_BUFFER_BIT);
6192 checkGLcall("glClear");
6194 if (This->render_offscreen) {
6195 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6197 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6198 checkGLcall("glBindFramebuffer()");
6201 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6202 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6203 glDrawBuffer(GL_BACK);
6204 checkGLcall("glDrawBuffer()");
6208 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6209 unsigned int r, g, b, a;
6212 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6213 destfmt == WINED3DFMT_R8G8B8)
6216 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6218 a = (color & 0xff000000) >> 24;
6219 r = (color & 0x00ff0000) >> 16;
6220 g = (color & 0x0000ff00) >> 8;
6221 b = (color & 0x000000ff) >> 0;
6225 case WINED3DFMT_R5G6B5:
6226 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6233 TRACE("Returning %08x\n", ret);
6236 case WINED3DFMT_X1R5G5B5:
6237 case WINED3DFMT_A1R5G5B5:
6246 TRACE("Returning %08x\n", ret);
6250 TRACE("Returning %08x\n", a);
6253 case WINED3DFMT_X4R4G4B4:
6254 case WINED3DFMT_A4R4G4B4:
6263 TRACE("Returning %08x\n", ret);
6266 case WINED3DFMT_R3G3B2:
6273 TRACE("Returning %08x\n", ret);
6276 case WINED3DFMT_X8B8G8R8:
6277 case WINED3DFMT_A8B8G8R8:
6282 TRACE("Returning %08x\n", ret);
6285 case WINED3DFMT_A2R10G10B10:
6287 r = (r * 1024) / 256;
6288 g = (g * 1024) / 256;
6289 b = (b * 1024) / 256;
6294 TRACE("Returning %08x\n", ret);
6297 case WINED3DFMT_A2B10G10R10:
6299 r = (r * 1024) / 256;
6300 g = (g * 1024) / 256;
6301 b = (b * 1024) / 256;
6306 TRACE("Returning %08x\n", ret);
6310 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6315 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6317 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6319 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6321 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6322 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6323 return WINED3DERR_INVALIDCALL;
6326 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6328 color_fill_fbo(iface, pSurface, pRect, color);
6332 /* Just forward this to the DirectDraw blitting engine */
6333 memset(&BltFx, 0, sizeof(BltFx));
6334 BltFx.dwSize = sizeof(BltFx);
6335 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6336 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6340 /* rendertarget and depth stencil functions */
6341 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6344 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6345 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6346 return WINED3DERR_INVALIDCALL;
6349 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6350 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6351 /* Note inc ref on returned surface */
6352 if(*ppRenderTarget != NULL)
6353 IWineD3DSurface_AddRef(*ppRenderTarget);
6357 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6359 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6360 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6361 IWineD3DSwapChainImpl *Swapchain;
6364 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6366 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6367 if(hr != WINED3D_OK) {
6368 ERR("Can't get the swapchain\n");
6372 /* Make sure to release the swapchain */
6373 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6375 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6376 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6377 return WINED3DERR_INVALIDCALL;
6379 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6380 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6381 return WINED3DERR_INVALIDCALL;
6384 if(Swapchain->frontBuffer != Front) {
6385 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6387 if(Swapchain->frontBuffer)
6388 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6389 Swapchain->frontBuffer = Front;
6391 if(Swapchain->frontBuffer) {
6392 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6396 if(Back && !Swapchain->backBuffer) {
6397 /* We need memory for the back buffer array - only one back buffer this way */
6398 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6399 if(!Swapchain->backBuffer) {
6400 ERR("Out of memory\n");
6401 return E_OUTOFMEMORY;
6405 if(Swapchain->backBuffer[0] != Back) {
6406 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6408 /* What to do about the context here in the case of multithreading? Not sure.
6409 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6412 if(!Swapchain->backBuffer[0]) {
6413 /* GL was told to draw to the front buffer at creation,
6416 glDrawBuffer(GL_BACK);
6417 checkGLcall("glDrawBuffer(GL_BACK)");
6418 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6419 Swapchain->presentParms.BackBufferCount = 1;
6421 /* That makes problems - disable for now */
6422 /* glDrawBuffer(GL_FRONT); */
6423 checkGLcall("glDrawBuffer(GL_FRONT)");
6424 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6425 Swapchain->presentParms.BackBufferCount = 0;
6429 if(Swapchain->backBuffer[0])
6430 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6431 Swapchain->backBuffer[0] = Back;
6433 if(Swapchain->backBuffer[0]) {
6434 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6436 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6437 Swapchain->backBuffer = NULL;
6445 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6447 *ppZStencilSurface = This->stencilBufferTarget;
6448 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6450 if(*ppZStencilSurface != NULL) {
6451 /* Note inc ref on returned surface */
6452 IWineD3DSurface_AddRef(*ppZStencilSurface);
6455 return WINED3DERR_NOTFOUND;
6459 /* TODO: Handle stencil attachments */
6460 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6463 TRACE("Set depth stencil to %p\n", depth_stencil);
6465 if (depth_stencil) {
6466 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6468 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6469 checkGLcall("glFramebufferTexture2DEXT()");
6473 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6476 TRACE("Set render target %u to %p\n", idx, render_target);
6478 if (render_target) {
6479 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6480 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6482 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6483 checkGLcall("glFramebufferTexture2DEXT()");
6485 This->draw_buffers[idx] = GL_NONE;
6489 static void check_fbo_status(IWineD3DDevice *iface) {
6490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6493 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6494 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6495 TRACE("FBO complete\n");
6497 IWineD3DSurfaceImpl *attachment;
6499 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6501 /* Dump the FBO attachments */
6502 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6503 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6505 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6506 attachment->pow2Width, attachment->pow2Height);
6509 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6511 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6512 attachment->pow2Width, attachment->pow2Height);
6517 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6519 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6520 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6522 if (!ds_impl) return FALSE;
6524 if (ds_impl->current_renderbuffer) {
6525 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6526 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6529 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6530 rt_impl->pow2Height != ds_impl->pow2Height);
6533 void apply_fbo_state(IWineD3DDevice *iface) {
6534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6537 if (This->render_offscreen) {
6538 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6540 /* Apply render targets */
6541 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6542 IWineD3DSurface *render_target = This->render_targets[i];
6543 if (This->fbo_color_attachments[i] != render_target) {
6544 set_render_target_fbo(iface, i, render_target);
6545 This->fbo_color_attachments[i] = render_target;
6549 /* Apply depth targets */
6550 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6551 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6552 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6554 if (This->stencilBufferTarget) {
6555 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6557 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6558 This->fbo_depth_attachment = This->stencilBufferTarget;
6561 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6562 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6563 checkGLcall("glDrawBuffers()");
6565 glDrawBuffer(This->draw_buffers[0]);
6566 checkGLcall("glDrawBuffer()");
6569 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6572 check_fbo_status(iface);
6575 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6576 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6578 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6579 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6582 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6583 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6584 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6585 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6588 case WINED3DTEXF_LINEAR:
6589 gl_filter = GL_LINEAR;
6593 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6594 case WINED3DTEXF_NONE:
6595 case WINED3DTEXF_POINT:
6596 gl_filter = GL_NEAREST;
6600 /* Attach src surface to src fbo */
6601 src_swapchain = get_swapchain(src_surface);
6602 if (src_swapchain) {
6605 TRACE("Source surface %p is onscreen\n", src_surface);
6606 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6607 /* Make sure the drawable is up to date. In the offscreen case
6608 * attach_surface_fbo() implicitly takes care of this. */
6609 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6612 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6613 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6614 glReadBuffer(buffer);
6615 checkGLcall("glReadBuffer()");
6617 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6618 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6620 TRACE("Source surface %p is offscreen\n", src_surface);
6622 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6623 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6624 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6625 checkGLcall("glReadBuffer()");
6626 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6627 checkGLcall("glFramebufferRenderbufferEXT");
6631 /* Attach dst surface to dst fbo */
6632 dst_swapchain = get_swapchain(dst_surface);
6633 if (dst_swapchain) {
6636 TRACE("Destination surface %p is onscreen\n", dst_surface);
6637 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6638 /* Make sure the drawable is up to date. In the offscreen case
6639 * attach_surface_fbo() implicitly takes care of this. */
6640 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6643 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6644 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6645 glDrawBuffer(buffer);
6646 checkGLcall("glDrawBuffer()");
6648 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6649 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6651 TRACE("Destination surface %p is offscreen\n", dst_surface);
6653 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6654 if(!src_swapchain) {
6655 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6659 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6660 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6661 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6662 checkGLcall("glDrawBuffer()");
6663 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6664 checkGLcall("glFramebufferRenderbufferEXT");
6666 glDisable(GL_SCISSOR_TEST);
6667 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6670 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6671 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6672 checkGLcall("glBlitFramebuffer()");
6674 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6675 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6676 checkGLcall("glBlitFramebuffer()");
6679 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6681 if (This->render_offscreen) {
6682 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6684 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6685 checkGLcall("glBindFramebuffer()");
6688 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6689 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6690 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6691 glDrawBuffer(GL_BACK);
6692 checkGLcall("glDrawBuffer()");
6697 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6699 WINED3DVIEWPORT viewport;
6701 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6703 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6704 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6705 This, RenderTargetIndex, GL_LIMITS(buffers));
6706 return WINED3DERR_INVALIDCALL;
6709 /* MSDN says that null disables the render target
6710 but a device must always be associated with a render target
6711 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6713 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6714 FIXME("Trying to set render target 0 to NULL\n");
6715 return WINED3DERR_INVALIDCALL;
6717 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6718 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);
6719 return WINED3DERR_INVALIDCALL;
6722 /* If we are trying to set what we already have, don't bother */
6723 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6724 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6727 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6728 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6729 This->render_targets[RenderTargetIndex] = pRenderTarget;
6731 /* Render target 0 is special */
6732 if(RenderTargetIndex == 0) {
6733 /* Finally, reset the viewport as the MSDN states. */
6734 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6735 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6738 viewport.MaxZ = 1.0f;
6739 viewport.MinZ = 0.0f;
6740 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6741 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6742 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6749 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6751 HRESULT hr = WINED3D_OK;
6752 IWineD3DSurface *tmp;
6754 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6756 if (pNewZStencil == This->stencilBufferTarget) {
6757 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6759 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6760 * depending on the renter target implementation being used.
6761 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6762 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6763 * stencil buffer and incur an extra memory overhead
6764 ******************************************************/
6766 if (This->stencilBufferTarget) {
6767 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6768 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6769 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6772 tmp = This->stencilBufferTarget;
6773 This->stencilBufferTarget = pNewZStencil;
6774 /* should we be calling the parent or the wined3d surface? */
6775 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6776 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6779 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6780 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6782 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6790 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6791 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6793 /* TODO: the use of Impl is deprecated. */
6794 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6795 WINED3DLOCKED_RECT lockedRect;
6797 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6799 /* some basic validation checks */
6800 if(This->cursorTexture) {
6801 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6803 glDeleteTextures(1, &This->cursorTexture);
6805 This->cursorTexture = 0;
6808 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6809 This->haveHardwareCursor = TRUE;
6811 This->haveHardwareCursor = FALSE;
6814 WINED3DLOCKED_RECT rect;
6816 /* MSDN: Cursor must be A8R8G8B8 */
6817 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6818 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6819 return WINED3DERR_INVALIDCALL;
6822 /* MSDN: Cursor must be smaller than the display mode */
6823 if(pSur->currentDesc.Width > This->ddraw_width ||
6824 pSur->currentDesc.Height > This->ddraw_height) {
6825 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);
6826 return WINED3DERR_INVALIDCALL;
6829 if (!This->haveHardwareCursor) {
6830 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6832 /* Do not store the surface's pointer because the application may
6833 * release it after setting the cursor image. Windows doesn't
6834 * addref the set surface, so we can't do this either without
6835 * creating circular refcount dependencies. Copy out the gl texture
6838 This->cursorWidth = pSur->currentDesc.Width;
6839 This->cursorHeight = pSur->currentDesc.Height;
6840 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6842 const GlPixelFormatDesc *glDesc;
6843 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6844 char *mem, *bits = (char *)rect.pBits;
6845 GLint intfmt = glDesc->glInternal;
6846 GLint format = glDesc->glFormat;
6847 GLint type = glDesc->glType;
6848 INT height = This->cursorHeight;
6849 INT width = This->cursorWidth;
6850 INT bpp = tableEntry->bpp;
6853 /* Reformat the texture memory (pitch and width can be
6855 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6856 for(i = 0; i < height; i++)
6857 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6858 IWineD3DSurface_UnlockRect(pCursorBitmap);
6861 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6862 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6863 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6866 /* Make sure that a proper texture unit is selected */
6867 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6868 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6869 checkGLcall("glActiveTextureARB");
6871 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6872 /* Create a new cursor texture */
6873 glGenTextures(1, &This->cursorTexture);
6874 checkGLcall("glGenTextures");
6875 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6876 checkGLcall("glBindTexture");
6877 /* Copy the bitmap memory into the cursor texture */
6878 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6879 HeapFree(GetProcessHeap(), 0, mem);
6880 checkGLcall("glTexImage2D");
6882 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6883 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6884 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6891 FIXME("A cursor texture was not returned.\n");
6892 This->cursorTexture = 0;
6897 /* Draw a hardware cursor */
6898 ICONINFO cursorInfo;
6900 /* Create and clear maskBits because it is not needed for
6901 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6903 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6904 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6905 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6906 WINED3DLOCK_NO_DIRTY_UPDATE |
6907 WINED3DLOCK_READONLY
6909 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6910 pSur->currentDesc.Height);
6912 cursorInfo.fIcon = FALSE;
6913 cursorInfo.xHotspot = XHotSpot;
6914 cursorInfo.yHotspot = YHotSpot;
6915 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6916 pSur->currentDesc.Height, 1,
6918 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6919 pSur->currentDesc.Height, 1,
6920 32, lockedRect.pBits);
6921 IWineD3DSurface_UnlockRect(pCursorBitmap);
6922 /* Create our cursor and clean up. */
6923 cursor = CreateIconIndirect(&cursorInfo);
6925 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6926 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6927 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6928 This->hardwareCursor = cursor;
6929 HeapFree(GetProcessHeap(), 0, maskBits);
6933 This->xHotSpot = XHotSpot;
6934 This->yHotSpot = YHotSpot;
6938 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6940 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6942 This->xScreenSpace = XScreenSpace;
6943 This->yScreenSpace = YScreenSpace;
6949 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6951 BOOL oldVisible = This->bCursorVisible;
6954 TRACE("(%p) : visible(%d)\n", This, bShow);
6957 * When ShowCursor is first called it should make the cursor appear at the OS's last
6958 * known cursor position. Because of this, some applications just repetitively call
6959 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6962 This->xScreenSpace = pt.x;
6963 This->yScreenSpace = pt.y;
6965 if (This->haveHardwareCursor) {
6966 This->bCursorVisible = bShow;
6968 SetCursor(This->hardwareCursor);
6974 if (This->cursorTexture)
6975 This->bCursorVisible = bShow;
6981 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6983 IWineD3DResourceImpl *resource;
6984 TRACE("(%p) : state (%u)\n", This, This->state);
6986 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6987 switch (This->state) {
6990 case WINED3DERR_DEVICELOST:
6992 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6993 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6994 return WINED3DERR_DEVICENOTRESET;
6996 return WINED3DERR_DEVICELOST;
6998 case WINED3DERR_DRIVERINTERNALERROR:
6999 return WINED3DERR_DRIVERINTERNALERROR;
7003 return WINED3DERR_DRIVERINTERNALERROR;
7007 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 /** FIXME: Resource tracking needs to be done,
7010 * The closes we can do to this is set the priorities of all managed textures low
7011 * and then reset them.
7012 ***********************************************************/
7013 FIXME("(%p) : stub\n", This);
7017 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7018 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7020 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7021 if(surface->Flags & SFLAG_DIBSECTION) {
7022 /* Release the DC */
7023 SelectObject(surface->hDC, surface->dib.holdbitmap);
7024 DeleteDC(surface->hDC);
7025 /* Release the DIB section */
7026 DeleteObject(surface->dib.DIBsection);
7027 surface->dib.bitmap_data = NULL;
7028 surface->resource.allocatedMemory = NULL;
7029 surface->Flags &= ~SFLAG_DIBSECTION;
7031 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7032 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7033 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7034 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7035 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7037 surface->pow2Width = surface->pow2Height = 1;
7038 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7039 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7041 surface->glRect.left = 0;
7042 surface->glRect.top = 0;
7043 surface->glRect.right = surface->pow2Width;
7044 surface->glRect.bottom = surface->pow2Height;
7046 if(surface->glDescription.textureName) {
7047 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7049 glDeleteTextures(1, &surface->glDescription.textureName);
7051 surface->glDescription.textureName = 0;
7052 surface->Flags &= ~SFLAG_CLIENT;
7054 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7055 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7056 surface->Flags |= SFLAG_NONPOW2;
7058 surface->Flags &= ~SFLAG_NONPOW2;
7060 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7061 surface->resource.allocatedMemory = NULL;
7062 surface->resource.heapMemory = NULL;
7063 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7064 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7065 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7066 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7068 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7072 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7073 TRACE("Unloading resource %p\n", resource);
7074 IWineD3DResource_UnLoad(resource);
7075 IWineD3DResource_Release(resource);
7079 static void reset_fbo_state(IWineD3DDevice *iface) {
7080 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7084 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7085 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7088 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7091 if (This->src_fbo) {
7092 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7095 if (This->dst_fbo) {
7096 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7099 checkGLcall("Tear down FBOs\n");
7102 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7103 This->fbo_color_attachments[i] = NULL;
7105 This->fbo_depth_attachment = NULL;
7108 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7110 WINED3DDISPLAYMODE m;
7113 /* All Windowed modes are supported, as is leaving the current mode */
7114 if(pp->Windowed) return TRUE;
7115 if(!pp->BackBufferWidth) return TRUE;
7116 if(!pp->BackBufferHeight) return TRUE;
7118 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7119 for(i = 0; i < count; i++) {
7120 memset(&m, 0, sizeof(m));
7121 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7123 ERR("EnumAdapterModes failed\n");
7125 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7126 /* Mode found, it is supported */
7130 /* Mode not found -> not supported */
7134 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7136 IWineD3DSwapChainImpl *swapchain;
7138 BOOL DisplayModeChanged = FALSE;
7139 WINED3DDISPLAYMODE mode;
7140 IWineD3DBaseShaderImpl *shader;
7141 IWineD3DSurfaceImpl *target;
7143 TRACE("(%p)\n", This);
7145 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7147 ERR("Failed to get the first implicit swapchain\n");
7151 if(!is_display_mode_supported(This, pPresentationParameters)) {
7152 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7153 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7154 pPresentationParameters->BackBufferHeight);
7155 return WINED3DERR_INVALIDCALL;
7158 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7159 * on an existing gl context, so there's no real need for recreation.
7161 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7163 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7165 TRACE("New params:\n");
7166 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7167 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7168 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7169 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7170 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7171 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7172 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7173 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7174 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7175 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7176 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7177 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7178 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7180 /* No special treatment of these parameters. Just store them */
7181 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7182 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7183 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7184 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7186 /* What to do about these? */
7187 if(pPresentationParameters->BackBufferCount != 0 &&
7188 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7189 ERR("Cannot change the back buffer count yet\n");
7191 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7192 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7193 ERR("Cannot change the back buffer format yet\n");
7195 if(pPresentationParameters->hDeviceWindow != NULL &&
7196 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7197 ERR("Cannot change the device window yet\n");
7199 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7200 ERR("What do do about a changed auto depth stencil parameter?\n");
7203 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7204 reset_fbo_state((IWineD3DDevice *) This);
7207 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7208 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7209 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7213 if(This->depth_blt_texture) {
7214 glDeleteTextures(1, &This->depth_blt_texture);
7215 This->depth_blt_texture = 0;
7217 if (This->depth_blt_rb) {
7218 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7219 This->depth_blt_rb = 0;
7220 This->depth_blt_rb_w = 0;
7221 This->depth_blt_rb_h = 0;
7223 This->shader_backend->shader_destroy_depth_blt(iface);
7224 This->shader_backend->shader_free_private(iface);
7226 for (i = 0; i < GL_LIMITS(textures); i++) {
7227 /* Textures are recreated below */
7228 glDeleteTextures(1, &This->dummyTextureName[i]);
7229 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7230 This->dummyTextureName[i] = 0;
7234 while(This->numContexts) {
7235 DestroyContext(This, This->contexts[0]);
7237 This->activeContext = NULL;
7238 HeapFree(GetProcessHeap(), 0, swapchain->context);
7239 swapchain->context = NULL;
7240 swapchain->num_contexts = 0;
7242 if(pPresentationParameters->Windowed) {
7243 mode.Width = swapchain->orig_width;
7244 mode.Height = swapchain->orig_height;
7245 mode.RefreshRate = 0;
7246 mode.Format = swapchain->presentParms.BackBufferFormat;
7248 mode.Width = pPresentationParameters->BackBufferWidth;
7249 mode.Height = pPresentationParameters->BackBufferHeight;
7250 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7251 mode.Format = swapchain->presentParms.BackBufferFormat;
7254 /* Should Width == 800 && Height == 0 set 800x600? */
7255 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7256 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7257 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7264 vp.Width = pPresentationParameters->BackBufferWidth;
7265 vp.Height = pPresentationParameters->BackBufferHeight;
7269 if(!pPresentationParameters->Windowed) {
7270 DisplayModeChanged = TRUE;
7272 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7273 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7275 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7276 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7277 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7279 if(This->auto_depth_stencil_buffer) {
7280 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7284 /* Now set the new viewport */
7285 IWineD3DDevice_SetViewport(iface, &vp);
7288 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7289 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7290 DisplayModeChanged) {
7292 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7293 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7294 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7295 } else if(!pPresentationParameters->Windowed) {
7296 DWORD style = This->style, exStyle = This->exStyle;
7297 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7298 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7299 * Reset to clear up their mess. Guild Wars also loses the device during that.
7303 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7304 This->style = style;
7305 This->exStyle = exStyle;
7308 /* Recreate the primary swapchain's context */
7309 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7310 if(swapchain->backBuffer) {
7311 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7313 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7315 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7316 &swapchain->presentParms);
7317 swapchain->num_contexts = 1;
7318 This->activeContext = swapchain->context[0];
7319 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7321 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7323 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7325 create_dummy_textures(This);
7328 hr = This->shader_backend->shader_alloc_private(iface);
7330 ERR("Failed to recreate shader private data\n");
7334 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7340 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7342 /** FIXME: always true at the moment **/
7343 if(!bEnableDialogs) {
7344 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7350 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7352 TRACE("(%p) : pParameters %p\n", This, pParameters);
7354 *pParameters = This->createParms;
7358 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7359 IWineD3DSwapChain *swapchain;
7361 TRACE("Relaying to swapchain\n");
7363 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7364 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7365 IWineD3DSwapChain_Release(swapchain);
7370 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7371 IWineD3DSwapChain *swapchain;
7373 TRACE("Relaying to swapchain\n");
7375 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7376 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7377 IWineD3DSwapChain_Release(swapchain);
7383 /** ********************************************************
7384 * Notification functions
7385 ** ********************************************************/
7386 /** This function must be called in the release of a resource when ref == 0,
7387 * the contents of resource must still be correct,
7388 * any handles to other resource held by the caller must be closed
7389 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7390 *****************************************************/
7391 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7394 TRACE("(%p) : Adding Resource %p\n", This, resource);
7395 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7398 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7401 TRACE("(%p) : Removing resource %p\n", This, resource);
7403 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7407 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7411 TRACE("(%p) : resource %p\n", This, resource);
7412 switch(IWineD3DResource_GetType(resource)){
7413 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7414 case WINED3DRTYPE_SURFACE: {
7417 /* Cleanup any FBO attachments if d3d is enabled */
7418 if(This->d3d_initialized) {
7419 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7420 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7422 TRACE("Last active render target destroyed\n");
7423 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7424 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7425 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7426 * and the lastActiveRenderTarget member shouldn't matter
7429 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7430 TRACE("Activating primary back buffer\n");
7431 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7432 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7433 /* Single buffering environment */
7434 TRACE("Activating primary front buffer\n");
7435 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7437 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7438 /* Implicit render target destroyed, that means the device is being destroyed
7439 * whatever we set here, it shouldn't matter
7441 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7444 /* May happen during ddraw uninitialization */
7445 TRACE("Render target set, but swapchain does not exist!\n");
7446 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7451 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7452 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7453 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7454 set_render_target_fbo(iface, i, NULL);
7455 This->fbo_color_attachments[i] = NULL;
7458 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7459 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7460 set_depth_stencil_fbo(iface, NULL);
7461 This->fbo_depth_attachment = NULL;
7468 case WINED3DRTYPE_TEXTURE:
7469 case WINED3DRTYPE_CUBETEXTURE:
7470 case WINED3DRTYPE_VOLUMETEXTURE:
7471 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7472 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7473 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7474 This->stateBlock->textures[counter] = NULL;
7476 if (This->updateStateBlock != This->stateBlock ){
7477 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7478 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7479 This->updateStateBlock->textures[counter] = NULL;
7484 case WINED3DRTYPE_VOLUME:
7485 /* TODO: nothing really? */
7487 case WINED3DRTYPE_VERTEXBUFFER:
7488 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7491 TRACE("Cleaning up stream pointers\n");
7493 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7494 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7495 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7497 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7498 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7499 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7500 This->updateStateBlock->streamSource[streamNumber] = 0;
7501 /* Set changed flag? */
7504 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) */
7505 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7506 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7507 This->stateBlock->streamSource[streamNumber] = 0;
7510 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7511 else { /* This shouldn't happen */
7512 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7519 case WINED3DRTYPE_INDEXBUFFER:
7520 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7521 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7522 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7523 This->updateStateBlock->pIndexData = NULL;
7526 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7527 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7528 This->stateBlock->pIndexData = NULL;
7534 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7539 /* Remove the resource from the resourceStore */
7540 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7542 TRACE("Resource released\n");
7546 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7548 IWineD3DResourceImpl *resource, *cursor;
7550 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7552 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7553 TRACE("enumerating resource %p\n", resource);
7554 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7555 ret = pCallback((IWineD3DResource *) resource, pData);
7556 if(ret == S_FALSE) {
7557 TRACE("Canceling enumeration\n");
7564 /**********************************************************
7565 * IWineD3DDevice VTbl follows
7566 **********************************************************/
7568 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7570 /*** IUnknown methods ***/
7571 IWineD3DDeviceImpl_QueryInterface,
7572 IWineD3DDeviceImpl_AddRef,
7573 IWineD3DDeviceImpl_Release,
7574 /*** IWineD3DDevice methods ***/
7575 IWineD3DDeviceImpl_GetParent,
7576 /*** Creation methods**/
7577 IWineD3DDeviceImpl_CreateVertexBuffer,
7578 IWineD3DDeviceImpl_CreateIndexBuffer,
7579 IWineD3DDeviceImpl_CreateStateBlock,
7580 IWineD3DDeviceImpl_CreateSurface,
7581 IWineD3DDeviceImpl_CreateTexture,
7582 IWineD3DDeviceImpl_CreateVolumeTexture,
7583 IWineD3DDeviceImpl_CreateVolume,
7584 IWineD3DDeviceImpl_CreateCubeTexture,
7585 IWineD3DDeviceImpl_CreateQuery,
7586 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7587 IWineD3DDeviceImpl_CreateVertexDeclaration,
7588 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7589 IWineD3DDeviceImpl_CreateVertexShader,
7590 IWineD3DDeviceImpl_CreatePixelShader,
7591 IWineD3DDeviceImpl_CreatePalette,
7592 /*** Odd functions **/
7593 IWineD3DDeviceImpl_Init3D,
7594 IWineD3DDeviceImpl_Uninit3D,
7595 IWineD3DDeviceImpl_SetFullscreen,
7596 IWineD3DDeviceImpl_SetMultithreaded,
7597 IWineD3DDeviceImpl_EvictManagedResources,
7598 IWineD3DDeviceImpl_GetAvailableTextureMem,
7599 IWineD3DDeviceImpl_GetBackBuffer,
7600 IWineD3DDeviceImpl_GetCreationParameters,
7601 IWineD3DDeviceImpl_GetDeviceCaps,
7602 IWineD3DDeviceImpl_GetDirect3D,
7603 IWineD3DDeviceImpl_GetDisplayMode,
7604 IWineD3DDeviceImpl_SetDisplayMode,
7605 IWineD3DDeviceImpl_GetHWND,
7606 IWineD3DDeviceImpl_SetHWND,
7607 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7608 IWineD3DDeviceImpl_GetRasterStatus,
7609 IWineD3DDeviceImpl_GetSwapChain,
7610 IWineD3DDeviceImpl_Reset,
7611 IWineD3DDeviceImpl_SetDialogBoxMode,
7612 IWineD3DDeviceImpl_SetCursorProperties,
7613 IWineD3DDeviceImpl_SetCursorPosition,
7614 IWineD3DDeviceImpl_ShowCursor,
7615 IWineD3DDeviceImpl_TestCooperativeLevel,
7616 /*** Getters and setters **/
7617 IWineD3DDeviceImpl_SetClipPlane,
7618 IWineD3DDeviceImpl_GetClipPlane,
7619 IWineD3DDeviceImpl_SetClipStatus,
7620 IWineD3DDeviceImpl_GetClipStatus,
7621 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7622 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7623 IWineD3DDeviceImpl_SetDepthStencilSurface,
7624 IWineD3DDeviceImpl_GetDepthStencilSurface,
7625 IWineD3DDeviceImpl_SetFVF,
7626 IWineD3DDeviceImpl_GetFVF,
7627 IWineD3DDeviceImpl_SetGammaRamp,
7628 IWineD3DDeviceImpl_GetGammaRamp,
7629 IWineD3DDeviceImpl_SetIndices,
7630 IWineD3DDeviceImpl_GetIndices,
7631 IWineD3DDeviceImpl_SetBaseVertexIndex,
7632 IWineD3DDeviceImpl_GetBaseVertexIndex,
7633 IWineD3DDeviceImpl_SetLight,
7634 IWineD3DDeviceImpl_GetLight,
7635 IWineD3DDeviceImpl_SetLightEnable,
7636 IWineD3DDeviceImpl_GetLightEnable,
7637 IWineD3DDeviceImpl_SetMaterial,
7638 IWineD3DDeviceImpl_GetMaterial,
7639 IWineD3DDeviceImpl_SetNPatchMode,
7640 IWineD3DDeviceImpl_GetNPatchMode,
7641 IWineD3DDeviceImpl_SetPaletteEntries,
7642 IWineD3DDeviceImpl_GetPaletteEntries,
7643 IWineD3DDeviceImpl_SetPixelShader,
7644 IWineD3DDeviceImpl_GetPixelShader,
7645 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7646 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7647 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7648 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7649 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7650 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7651 IWineD3DDeviceImpl_SetRenderState,
7652 IWineD3DDeviceImpl_GetRenderState,
7653 IWineD3DDeviceImpl_SetRenderTarget,
7654 IWineD3DDeviceImpl_GetRenderTarget,
7655 IWineD3DDeviceImpl_SetFrontBackBuffers,
7656 IWineD3DDeviceImpl_SetSamplerState,
7657 IWineD3DDeviceImpl_GetSamplerState,
7658 IWineD3DDeviceImpl_SetScissorRect,
7659 IWineD3DDeviceImpl_GetScissorRect,
7660 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7661 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7662 IWineD3DDeviceImpl_SetStreamSource,
7663 IWineD3DDeviceImpl_GetStreamSource,
7664 IWineD3DDeviceImpl_SetStreamSourceFreq,
7665 IWineD3DDeviceImpl_GetStreamSourceFreq,
7666 IWineD3DDeviceImpl_SetTexture,
7667 IWineD3DDeviceImpl_GetTexture,
7668 IWineD3DDeviceImpl_SetTextureStageState,
7669 IWineD3DDeviceImpl_GetTextureStageState,
7670 IWineD3DDeviceImpl_SetTransform,
7671 IWineD3DDeviceImpl_GetTransform,
7672 IWineD3DDeviceImpl_SetVertexDeclaration,
7673 IWineD3DDeviceImpl_GetVertexDeclaration,
7674 IWineD3DDeviceImpl_SetVertexShader,
7675 IWineD3DDeviceImpl_GetVertexShader,
7676 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7677 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7678 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7679 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7680 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7681 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7682 IWineD3DDeviceImpl_SetViewport,
7683 IWineD3DDeviceImpl_GetViewport,
7684 IWineD3DDeviceImpl_MultiplyTransform,
7685 IWineD3DDeviceImpl_ValidateDevice,
7686 IWineD3DDeviceImpl_ProcessVertices,
7687 /*** State block ***/
7688 IWineD3DDeviceImpl_BeginStateBlock,
7689 IWineD3DDeviceImpl_EndStateBlock,
7690 /*** Scene management ***/
7691 IWineD3DDeviceImpl_BeginScene,
7692 IWineD3DDeviceImpl_EndScene,
7693 IWineD3DDeviceImpl_Present,
7694 IWineD3DDeviceImpl_Clear,
7696 IWineD3DDeviceImpl_DrawPrimitive,
7697 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7698 IWineD3DDeviceImpl_DrawPrimitiveUP,
7699 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7700 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7701 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7702 IWineD3DDeviceImpl_DrawRectPatch,
7703 IWineD3DDeviceImpl_DrawTriPatch,
7704 IWineD3DDeviceImpl_DeletePatch,
7705 IWineD3DDeviceImpl_ColorFill,
7706 IWineD3DDeviceImpl_UpdateTexture,
7707 IWineD3DDeviceImpl_UpdateSurface,
7708 IWineD3DDeviceImpl_GetFrontBufferData,
7709 /*** object tracking ***/
7710 IWineD3DDeviceImpl_ResourceReleased,
7711 IWineD3DDeviceImpl_EnumResources
7714 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7716 /*** IUnknown methods ***/
7717 IWineD3DDeviceImpl_QueryInterface,
7718 IWineD3DDeviceImpl_AddRef,
7719 IWineD3DDeviceImpl_Release,
7720 /*** IWineD3DDevice methods ***/
7721 IWineD3DDeviceImpl_GetParent,
7722 /*** Creation methods**/
7723 IWineD3DDeviceImpl_CreateVertexBuffer,
7724 IWineD3DDeviceImpl_CreateIndexBuffer,
7725 IWineD3DDeviceImpl_CreateStateBlock,
7726 IWineD3DDeviceImpl_CreateSurface,
7727 IWineD3DDeviceImpl_CreateTexture,
7728 IWineD3DDeviceImpl_CreateVolumeTexture,
7729 IWineD3DDeviceImpl_CreateVolume,
7730 IWineD3DDeviceImpl_CreateCubeTexture,
7731 IWineD3DDeviceImpl_CreateQuery,
7732 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7733 IWineD3DDeviceImpl_CreateVertexDeclaration,
7734 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7735 IWineD3DDeviceImpl_CreateVertexShader,
7736 IWineD3DDeviceImpl_CreatePixelShader,
7737 IWineD3DDeviceImpl_CreatePalette,
7738 /*** Odd functions **/
7739 IWineD3DDeviceImpl_Init3D,
7740 IWineD3DDeviceImpl_Uninit3D,
7741 IWineD3DDeviceImpl_SetFullscreen,
7742 IWineD3DDeviceImpl_SetMultithreaded,
7743 IWineD3DDeviceImpl_EvictManagedResources,
7744 IWineD3DDeviceImpl_GetAvailableTextureMem,
7745 IWineD3DDeviceImpl_GetBackBuffer,
7746 IWineD3DDeviceImpl_GetCreationParameters,
7747 IWineD3DDeviceImpl_GetDeviceCaps,
7748 IWineD3DDeviceImpl_GetDirect3D,
7749 IWineD3DDeviceImpl_GetDisplayMode,
7750 IWineD3DDeviceImpl_SetDisplayMode,
7751 IWineD3DDeviceImpl_GetHWND,
7752 IWineD3DDeviceImpl_SetHWND,
7753 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7754 IWineD3DDeviceImpl_GetRasterStatus,
7755 IWineD3DDeviceImpl_GetSwapChain,
7756 IWineD3DDeviceImpl_Reset,
7757 IWineD3DDeviceImpl_SetDialogBoxMode,
7758 IWineD3DDeviceImpl_SetCursorProperties,
7759 IWineD3DDeviceImpl_SetCursorPosition,
7760 IWineD3DDeviceImpl_ShowCursor,
7761 IWineD3DDeviceImpl_TestCooperativeLevel,
7762 /*** Getters and setters **/
7763 IWineD3DDeviceImpl_SetClipPlane,
7764 IWineD3DDeviceImpl_GetClipPlane,
7765 IWineD3DDeviceImpl_SetClipStatus,
7766 IWineD3DDeviceImpl_GetClipStatus,
7767 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7768 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7769 IWineD3DDeviceImpl_SetDepthStencilSurface,
7770 IWineD3DDeviceImpl_GetDepthStencilSurface,
7771 IWineD3DDeviceImpl_SetFVF,
7772 IWineD3DDeviceImpl_GetFVF,
7773 IWineD3DDeviceImpl_SetGammaRamp,
7774 IWineD3DDeviceImpl_GetGammaRamp,
7775 IWineD3DDeviceImpl_SetIndices,
7776 IWineD3DDeviceImpl_GetIndices,
7777 IWineD3DDeviceImpl_SetBaseVertexIndex,
7778 IWineD3DDeviceImpl_GetBaseVertexIndex,
7779 IWineD3DDeviceImpl_SetLight,
7780 IWineD3DDeviceImpl_GetLight,
7781 IWineD3DDeviceImpl_SetLightEnable,
7782 IWineD3DDeviceImpl_GetLightEnable,
7783 IWineD3DDeviceImpl_SetMaterial,
7784 IWineD3DDeviceImpl_GetMaterial,
7785 IWineD3DDeviceImpl_SetNPatchMode,
7786 IWineD3DDeviceImpl_GetNPatchMode,
7787 IWineD3DDeviceImpl_SetPaletteEntries,
7788 IWineD3DDeviceImpl_GetPaletteEntries,
7789 IWineD3DDeviceImpl_SetPixelShader,
7790 IWineD3DDeviceImpl_GetPixelShader,
7791 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7792 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7793 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7794 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7795 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7796 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7797 IWineD3DDeviceImpl_SetRenderState,
7798 IWineD3DDeviceImpl_GetRenderState,
7799 IWineD3DDeviceImpl_SetRenderTarget,
7800 IWineD3DDeviceImpl_GetRenderTarget,
7801 IWineD3DDeviceImpl_SetFrontBackBuffers,
7802 IWineD3DDeviceImpl_SetSamplerState,
7803 IWineD3DDeviceImpl_GetSamplerState,
7804 IWineD3DDeviceImpl_SetScissorRect,
7805 IWineD3DDeviceImpl_GetScissorRect,
7806 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7807 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7808 IWineD3DDeviceImpl_SetStreamSource,
7809 IWineD3DDeviceImpl_GetStreamSource,
7810 IWineD3DDeviceImpl_SetStreamSourceFreq,
7811 IWineD3DDeviceImpl_GetStreamSourceFreq,
7812 IWineD3DDeviceImpl_SetTexture,
7813 IWineD3DDeviceImpl_GetTexture,
7814 IWineD3DDeviceImpl_SetTextureStageState,
7815 IWineD3DDeviceImpl_GetTextureStageState,
7816 IWineD3DDeviceImpl_SetTransform,
7817 IWineD3DDeviceImpl_GetTransform,
7818 IWineD3DDeviceImpl_SetVertexDeclaration,
7819 IWineD3DDeviceImpl_GetVertexDeclaration,
7820 IWineD3DDeviceImpl_SetVertexShader,
7821 IWineD3DDeviceImpl_GetVertexShader,
7822 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7823 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7824 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7825 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7826 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7827 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7828 IWineD3DDeviceImpl_SetViewport,
7829 IWineD3DDeviceImpl_GetViewport,
7830 IWineD3DDeviceImpl_MultiplyTransform,
7831 IWineD3DDeviceImpl_ValidateDevice,
7832 IWineD3DDeviceImpl_ProcessVertices,
7833 /*** State block ***/
7834 IWineD3DDeviceImpl_BeginStateBlock,
7835 IWineD3DDeviceImpl_EndStateBlock,
7836 /*** Scene management ***/
7837 IWineD3DDeviceImpl_BeginScene,
7838 IWineD3DDeviceImpl_EndScene,
7839 IWineD3DDeviceImpl_Present,
7840 IWineD3DDeviceImpl_Clear,
7842 IWineD3DDeviceImpl_DrawPrimitive,
7843 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7844 IWineD3DDeviceImpl_DrawPrimitiveUP,
7845 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7846 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7847 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7848 IWineD3DDeviceImpl_DrawRectPatch,
7849 IWineD3DDeviceImpl_DrawTriPatch,
7850 IWineD3DDeviceImpl_DeletePatch,
7851 IWineD3DDeviceImpl_ColorFill,
7852 IWineD3DDeviceImpl_UpdateTexture,
7853 IWineD3DDeviceImpl_UpdateSurface,
7854 IWineD3DDeviceImpl_GetFrontBufferData,
7855 /*** object tracking ***/
7856 IWineD3DDeviceImpl_ResourceReleased,
7857 IWineD3DDeviceImpl_EnumResources
7860 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7861 WINED3DRS_ALPHABLENDENABLE ,
7862 WINED3DRS_ALPHAFUNC ,
7863 WINED3DRS_ALPHAREF ,
7864 WINED3DRS_ALPHATESTENABLE ,
7866 WINED3DRS_COLORWRITEENABLE ,
7867 WINED3DRS_DESTBLEND ,
7868 WINED3DRS_DITHERENABLE ,
7869 WINED3DRS_FILLMODE ,
7870 WINED3DRS_FOGDENSITY ,
7872 WINED3DRS_FOGSTART ,
7873 WINED3DRS_LASTPIXEL ,
7874 WINED3DRS_SHADEMODE ,
7875 WINED3DRS_SRCBLEND ,
7876 WINED3DRS_STENCILENABLE ,
7877 WINED3DRS_STENCILFAIL ,
7878 WINED3DRS_STENCILFUNC ,
7879 WINED3DRS_STENCILMASK ,
7880 WINED3DRS_STENCILPASS ,
7881 WINED3DRS_STENCILREF ,
7882 WINED3DRS_STENCILWRITEMASK ,
7883 WINED3DRS_STENCILZFAIL ,
7884 WINED3DRS_TEXTUREFACTOR ,
7895 WINED3DRS_ZWRITEENABLE
7898 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7899 WINED3DTSS_ADDRESSW ,
7900 WINED3DTSS_ALPHAARG0 ,
7901 WINED3DTSS_ALPHAARG1 ,
7902 WINED3DTSS_ALPHAARG2 ,
7903 WINED3DTSS_ALPHAOP ,
7904 WINED3DTSS_BUMPENVLOFFSET ,
7905 WINED3DTSS_BUMPENVLSCALE ,
7906 WINED3DTSS_BUMPENVMAT00 ,
7907 WINED3DTSS_BUMPENVMAT01 ,
7908 WINED3DTSS_BUMPENVMAT10 ,
7909 WINED3DTSS_BUMPENVMAT11 ,
7910 WINED3DTSS_COLORARG0 ,
7911 WINED3DTSS_COLORARG1 ,
7912 WINED3DTSS_COLORARG2 ,
7913 WINED3DTSS_COLOROP ,
7914 WINED3DTSS_RESULTARG ,
7915 WINED3DTSS_TEXCOORDINDEX ,
7916 WINED3DTSS_TEXTURETRANSFORMFLAGS
7919 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7920 WINED3DSAMP_ADDRESSU ,
7921 WINED3DSAMP_ADDRESSV ,
7922 WINED3DSAMP_ADDRESSW ,
7923 WINED3DSAMP_BORDERCOLOR ,
7924 WINED3DSAMP_MAGFILTER ,
7925 WINED3DSAMP_MINFILTER ,
7926 WINED3DSAMP_MIPFILTER ,
7927 WINED3DSAMP_MIPMAPLODBIAS ,
7928 WINED3DSAMP_MAXMIPLEVEL ,
7929 WINED3DSAMP_MAXANISOTROPY ,
7930 WINED3DSAMP_SRGBTEXTURE ,
7931 WINED3DSAMP_ELEMENTINDEX
7934 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7936 WINED3DRS_AMBIENTMATERIALSOURCE ,
7937 WINED3DRS_CLIPPING ,
7938 WINED3DRS_CLIPPLANEENABLE ,
7939 WINED3DRS_COLORVERTEX ,
7940 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7941 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7942 WINED3DRS_FOGDENSITY ,
7944 WINED3DRS_FOGSTART ,
7945 WINED3DRS_FOGTABLEMODE ,
7946 WINED3DRS_FOGVERTEXMODE ,
7947 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7948 WINED3DRS_LIGHTING ,
7949 WINED3DRS_LOCALVIEWER ,
7950 WINED3DRS_MULTISAMPLEANTIALIAS ,
7951 WINED3DRS_MULTISAMPLEMASK ,
7952 WINED3DRS_NORMALIZENORMALS ,
7953 WINED3DRS_PATCHEDGESTYLE ,
7954 WINED3DRS_POINTSCALE_A ,
7955 WINED3DRS_POINTSCALE_B ,
7956 WINED3DRS_POINTSCALE_C ,
7957 WINED3DRS_POINTSCALEENABLE ,
7958 WINED3DRS_POINTSIZE ,
7959 WINED3DRS_POINTSIZE_MAX ,
7960 WINED3DRS_POINTSIZE_MIN ,
7961 WINED3DRS_POINTSPRITEENABLE ,
7962 WINED3DRS_RANGEFOGENABLE ,
7963 WINED3DRS_SPECULARMATERIALSOURCE ,
7964 WINED3DRS_TWEENFACTOR ,
7965 WINED3DRS_VERTEXBLEND ,
7966 WINED3DRS_CULLMODE ,
7970 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7971 WINED3DTSS_TEXCOORDINDEX ,
7972 WINED3DTSS_TEXTURETRANSFORMFLAGS
7975 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7976 WINED3DSAMP_DMAPOFFSET
7979 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7980 DWORD rep = This->StateTable[state].representative;
7984 WineD3DContext *context;
7987 for(i = 0; i < This->numContexts; i++) {
7988 context = This->contexts[i];
7989 if(isStateDirty(context, rep)) continue;
7991 context->dirtyArray[context->numDirtyEntries++] = rep;
7994 context->isStateDirty[idx] |= (1 << shift);
7998 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7999 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8000 /* The drawable size of a pbuffer render target is the current pbuffer size
8002 *width = dev->pbufferWidth;
8003 *height = dev->pbufferHeight;
8006 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8007 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8009 *width = This->pow2Width;
8010 *height = This->pow2Height;
8013 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8014 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8015 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8016 * current context's drawable, which is the size of the back buffer of the swapchain
8017 * the active context belongs to. The back buffer of the swapchain is stored as the
8018 * surface the context belongs to.
8020 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8021 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;