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 This->shader_backend->shader_destroy_depth_blt(iface);
2283 This->shader_backend->shader_free_private(iface);
2285 /* Release the update stateblock */
2286 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2287 if(This->updateStateBlock != This->stateBlock)
2288 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2290 This->updateStateBlock = NULL;
2292 { /* because were not doing proper internal refcounts releasing the primary state block
2293 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2294 to set this->stateBlock = NULL; first */
2295 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2296 This->stateBlock = NULL;
2298 /* Release the stateblock */
2299 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2300 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2304 /* Release the buffers (with sanity checks)*/
2305 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2306 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2307 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2308 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2310 This->stencilBufferTarget = NULL;
2312 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2313 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2314 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2316 TRACE("Setting rendertarget to NULL\n");
2317 This->render_targets[0] = NULL;
2319 if (This->auto_depth_stencil_buffer) {
2320 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2321 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2323 This->auto_depth_stencil_buffer = NULL;
2326 for(i=0; i < This->NumberOfSwapChains; i++) {
2327 TRACE("Releasing the implicit swapchain %d\n", i);
2328 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2329 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2333 HeapFree(GetProcessHeap(), 0, This->swapchains);
2334 This->swapchains = NULL;
2335 This->NumberOfSwapChains = 0;
2337 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2338 HeapFree(GetProcessHeap(), 0, This->palettes);
2339 This->palettes = NULL;
2340 This->NumberOfPalettes = 0;
2342 HeapFree(GetProcessHeap(), 0, This->render_targets);
2343 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2344 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2345 This->render_targets = NULL;
2346 This->fbo_color_attachments = NULL;
2347 This->draw_buffers = NULL;
2349 This->d3d_initialized = FALSE;
2353 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2355 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2357 /* Setup the window for fullscreen mode */
2358 if(fullscreen && !This->ddraw_fullscreen) {
2359 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2360 } else if(!fullscreen && This->ddraw_fullscreen) {
2361 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2364 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2365 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2366 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2369 This->ddraw_fullscreen = fullscreen;
2372 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2373 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2374 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2376 * There is no way to deactivate thread safety once it is enabled.
2378 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2381 /*For now just store the flag(needed in case of ddraw) */
2382 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2387 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2391 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2394 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2396 /* Resize the screen even without a window:
2397 * The app could have unset it with SetCooperativeLevel, but not called
2398 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2399 * but we don't have any hwnd
2402 memset(&devmode, 0, sizeof(devmode));
2403 devmode.dmSize = sizeof(devmode);
2404 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2405 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2406 devmode.dmPelsWidth = pMode->Width;
2407 devmode.dmPelsHeight = pMode->Height;
2409 devmode.dmDisplayFrequency = pMode->RefreshRate;
2410 if (pMode->RefreshRate != 0) {
2411 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2414 /* Only change the mode if necessary */
2415 if( (This->ddraw_width == pMode->Width) &&
2416 (This->ddraw_height == pMode->Height) &&
2417 (This->ddraw_format == pMode->Format) &&
2418 (pMode->RefreshRate == 0) ) {
2422 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2423 if (ret != DISP_CHANGE_SUCCESSFUL) {
2424 if(devmode.dmDisplayFrequency != 0) {
2425 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2426 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2427 devmode.dmDisplayFrequency = 0;
2428 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2430 if(ret != DISP_CHANGE_SUCCESSFUL) {
2431 return WINED3DERR_NOTAVAILABLE;
2435 /* Store the new values */
2436 This->ddraw_width = pMode->Width;
2437 This->ddraw_height = pMode->Height;
2438 This->ddraw_format = pMode->Format;
2440 /* Only do this with a window of course, and only if we're fullscreened */
2441 if(This->ddraw_window && This->ddraw_fullscreen)
2442 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2444 /* And finally clip mouse to our screen */
2445 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2446 ClipCursor(&clip_rc);
2451 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2453 *ppD3D= This->wineD3D;
2454 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2455 IWineD3D_AddRef(*ppD3D);
2459 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2462 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2463 (This->adapter->TextureRam/(1024*1024)),
2464 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2465 /* return simulated texture memory left */
2466 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2474 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2477 /* Update the current state block */
2478 This->updateStateBlock->changed.fvf = TRUE;
2480 if(This->updateStateBlock->fvf == fvf) {
2481 TRACE("Application is setting the old fvf over, nothing to do\n");
2485 This->updateStateBlock->fvf = fvf;
2486 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2487 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2492 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2494 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2495 *pfvf = This->stateBlock->fvf;
2500 * Get / Set Stream Source
2502 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2504 IWineD3DVertexBuffer *oldSrc;
2506 if (StreamNumber >= MAX_STREAMS) {
2507 WARN("Stream out of range %d\n", StreamNumber);
2508 return WINED3DERR_INVALIDCALL;
2509 } else if(OffsetInBytes & 0x3) {
2510 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2511 return WINED3DERR_INVALIDCALL;
2514 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2515 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2517 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2519 if(oldSrc == pStreamData &&
2520 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2521 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2522 TRACE("Application is setting the old values over, nothing to do\n");
2526 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2528 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2529 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2532 /* Handle recording of state blocks */
2533 if (This->isRecordingState) {
2534 TRACE("Recording... not performing anything\n");
2535 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2536 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2540 /* Need to do a getParent and pass the references up */
2541 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2542 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2543 so for now, just count internally */
2544 if (pStreamData != NULL) {
2545 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2546 InterlockedIncrement(&vbImpl->bindCount);
2547 IWineD3DVertexBuffer_AddRef(pStreamData);
2549 if (oldSrc != NULL) {
2550 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2551 IWineD3DVertexBuffer_Release(oldSrc);
2554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2559 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2562 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2563 This->stateBlock->streamSource[StreamNumber],
2564 This->stateBlock->streamOffset[StreamNumber],
2565 This->stateBlock->streamStride[StreamNumber]);
2567 if (StreamNumber >= MAX_STREAMS) {
2568 WARN("Stream out of range %d\n", StreamNumber);
2569 return WINED3DERR_INVALIDCALL;
2571 *pStream = This->stateBlock->streamSource[StreamNumber];
2572 *pStride = This->stateBlock->streamStride[StreamNumber];
2574 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2577 if (*pStream != NULL) {
2578 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2583 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2585 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2586 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2588 /* Verify input at least in d3d9 this is invalid*/
2589 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2590 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2591 return WINED3DERR_INVALIDCALL;
2593 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2594 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2595 return WINED3DERR_INVALIDCALL;
2598 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2599 return WINED3DERR_INVALIDCALL;
2602 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2603 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2605 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2606 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2608 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2609 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2610 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2616 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2619 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2620 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2622 TRACE("(%p) : returning %d\n", This, *Divider);
2628 * Get / Set & Multiply Transform
2630 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 /* Most of this routine, comments included copied from ddraw tree initially: */
2634 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2636 /* Handle recording of state blocks */
2637 if (This->isRecordingState) {
2638 TRACE("Recording... not performing anything\n");
2639 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2640 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2645 * If the new matrix is the same as the current one,
2646 * we cut off any further processing. this seems to be a reasonable
2647 * optimization because as was noticed, some apps (warcraft3 for example)
2648 * tend towards setting the same matrix repeatedly for some reason.
2650 * From here on we assume that the new matrix is different, wherever it matters.
2652 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2653 TRACE("The app is setting the same matrix over again\n");
2656 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2660 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2661 where ViewMat = Camera space, WorldMat = world space.
2663 In OpenGL, camera and world space is combined into GL_MODELVIEW
2664 matrix. The Projection matrix stay projection matrix.
2667 /* Capture the times we can just ignore the change for now */
2668 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2669 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2670 /* Handled by the state manager */
2673 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2677 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2679 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2680 *pMatrix = This->stateBlock->transforms[State];
2684 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2685 WINED3DMATRIX *mat = NULL;
2688 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2689 * below means it will be recorded in a state block change, but it
2690 * works regardless where it is recorded.
2691 * If this is found to be wrong, change to StateBlock.
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2694 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2696 if (State < HIGHEST_TRANSFORMSTATE)
2698 mat = &This->updateStateBlock->transforms[State];
2700 FIXME("Unhandled transform state!!\n");
2703 multiply_matrix(&temp, mat, pMatrix);
2705 /* Apply change via set transform - will reapply to eg. lights this way */
2706 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2712 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2713 you can reference any indexes you want as long as that number max are enabled at any
2714 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2715 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2716 but when recording, just build a chain pretty much of commands to be replayed. */
2718 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2720 PLIGHTINFOEL *object = NULL;
2721 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2727 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2731 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2732 return WINED3DERR_INVALIDCALL;
2735 switch(pLight->Type) {
2736 case WINED3DLIGHT_POINT:
2737 case WINED3DLIGHT_SPOT:
2738 case WINED3DLIGHT_PARALLELPOINT:
2739 case WINED3DLIGHT_GLSPOT:
2740 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2743 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2744 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2745 return WINED3DERR_INVALIDCALL;
2749 case WINED3DLIGHT_DIRECTIONAL:
2750 /* Ignores attenuation */
2754 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2755 return WINED3DERR_INVALIDCALL;
2758 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2759 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2760 if(object->OriginalIndex == Index) break;
2765 TRACE("Adding new light\n");
2766 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2768 ERR("Out of memory error when allocating a light\n");
2769 return E_OUTOFMEMORY;
2771 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2772 object->glIndex = -1;
2773 object->OriginalIndex = Index;
2774 object->changed = TRUE;
2777 /* Initialize the object */
2778 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,
2779 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2780 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2781 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2782 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2783 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2784 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2786 /* Save away the information */
2787 object->OriginalParms = *pLight;
2789 switch (pLight->Type) {
2790 case WINED3DLIGHT_POINT:
2792 object->lightPosn[0] = pLight->Position.x;
2793 object->lightPosn[1] = pLight->Position.y;
2794 object->lightPosn[2] = pLight->Position.z;
2795 object->lightPosn[3] = 1.0f;
2796 object->cutoff = 180.0f;
2800 case WINED3DLIGHT_DIRECTIONAL:
2802 object->lightPosn[0] = -pLight->Direction.x;
2803 object->lightPosn[1] = -pLight->Direction.y;
2804 object->lightPosn[2] = -pLight->Direction.z;
2805 object->lightPosn[3] = 0.0;
2806 object->exponent = 0.0f;
2807 object->cutoff = 180.0f;
2810 case WINED3DLIGHT_SPOT:
2812 object->lightPosn[0] = pLight->Position.x;
2813 object->lightPosn[1] = pLight->Position.y;
2814 object->lightPosn[2] = pLight->Position.z;
2815 object->lightPosn[3] = 1.0;
2818 object->lightDirn[0] = pLight->Direction.x;
2819 object->lightDirn[1] = pLight->Direction.y;
2820 object->lightDirn[2] = pLight->Direction.z;
2821 object->lightDirn[3] = 1.0;
2824 * opengl-ish and d3d-ish spot lights use too different models for the
2825 * light "intensity" as a function of the angle towards the main light direction,
2826 * so we only can approximate very roughly.
2827 * however spot lights are rather rarely used in games (if ever used at all).
2828 * furthermore if still used, probably nobody pays attention to such details.
2830 if (pLight->Falloff == 0) {
2831 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2832 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2833 * will always be 1.0 for both of them, and we don't have to care for the
2834 * rest of the rather complex calculation
2836 object->exponent = 0;
2838 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2839 if (rho < 0.0001) rho = 0.0001f;
2840 object->exponent = -0.3/log(cos(rho/2));
2842 if (object->exponent > 128.0) {
2843 object->exponent = 128.0;
2845 object->cutoff = pLight->Phi*90/M_PI;
2851 FIXME("Unrecognized light type %d\n", pLight->Type);
2854 /* Update the live definitions if the light is currently assigned a glIndex */
2855 if (object->glIndex != -1 && !This->isRecordingState) {
2856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2861 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2862 PLIGHTINFOEL *lightInfo = NULL;
2863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2864 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2866 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2868 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2869 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2870 if(lightInfo->OriginalIndex == Index) break;
2874 if (lightInfo == NULL) {
2875 TRACE("Light information requested but light not defined\n");
2876 return WINED3DERR_INVALIDCALL;
2879 *pLight = lightInfo->OriginalParms;
2884 * Get / Set Light Enable
2885 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2887 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2888 PLIGHTINFOEL *lightInfo = NULL;
2889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2890 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2892 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2894 /* Tests show true = 128...not clear why */
2895 Enable = Enable? 128: 0;
2897 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2898 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2899 if(lightInfo->OriginalIndex == Index) break;
2902 TRACE("Found light: %p\n", lightInfo);
2904 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2905 if (lightInfo == NULL) {
2907 TRACE("Light enabled requested but light not defined, so defining one!\n");
2908 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2910 /* Search for it again! Should be fairly quick as near head of list */
2911 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2912 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2913 if(lightInfo->OriginalIndex == Index) break;
2916 if (lightInfo == NULL) {
2917 FIXME("Adding default lights has failed dismally\n");
2918 return WINED3DERR_INVALIDCALL;
2922 lightInfo->enabledChanged = TRUE;
2924 if(lightInfo->glIndex != -1) {
2925 if(!This->isRecordingState) {
2926 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2929 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2930 lightInfo->glIndex = -1;
2932 TRACE("Light already disabled, nothing to do\n");
2934 lightInfo->enabled = FALSE;
2936 lightInfo->enabled = TRUE;
2937 if (lightInfo->glIndex != -1) {
2939 TRACE("Nothing to do as light was enabled\n");
2942 /* Find a free gl light */
2943 for(i = 0; i < This->maxConcurrentLights; i++) {
2944 if(This->stateBlock->activeLights[i] == NULL) {
2945 This->stateBlock->activeLights[i] = lightInfo;
2946 lightInfo->glIndex = i;
2950 if(lightInfo->glIndex == -1) {
2951 /* Our tests show that Windows returns D3D_OK in this situation, even with
2952 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2953 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2954 * as well for those lights.
2956 * TODO: Test how this affects rendering
2958 FIXME("Too many concurrently active lights\n");
2962 /* i == lightInfo->glIndex */
2963 if(!This->isRecordingState) {
2964 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2972 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2974 PLIGHTINFOEL *lightInfo = NULL;
2975 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2977 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2978 TRACE("(%p) : for idx(%d)\n", This, Index);
2980 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2981 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2982 if(lightInfo->OriginalIndex == Index) break;
2986 if (lightInfo == NULL) {
2987 TRACE("Light enabled state requested but light not defined\n");
2988 return WINED3DERR_INVALIDCALL;
2990 /* true is 128 according to SetLightEnable */
2991 *pEnable = lightInfo->enabled ? 128 : 0;
2996 * Get / Set Clip Planes
2998 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
2999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3000 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3002 /* Validate Index */
3003 if (Index >= GL_LIMITS(clipplanes)) {
3004 TRACE("Application has requested clipplane this device doesn't support\n");
3005 return WINED3DERR_INVALIDCALL;
3008 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3010 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3011 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3012 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3013 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3014 TRACE("Application is setting old values over, nothing to do\n");
3018 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3019 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3020 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3021 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3023 /* Handle recording of state blocks */
3024 if (This->isRecordingState) {
3025 TRACE("Recording... not performing anything\n");
3029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3034 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3035 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3036 TRACE("(%p) : for idx %d\n", This, Index);
3038 /* Validate Index */
3039 if (Index >= GL_LIMITS(clipplanes)) {
3040 TRACE("Application has requested clipplane this device doesn't support\n");
3041 return WINED3DERR_INVALIDCALL;
3044 pPlane[0] = This->stateBlock->clipplane[Index][0];
3045 pPlane[1] = This->stateBlock->clipplane[Index][1];
3046 pPlane[2] = This->stateBlock->clipplane[Index][2];
3047 pPlane[3] = This->stateBlock->clipplane[Index][3];
3052 * Get / Set Clip Plane Status
3053 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3055 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3057 FIXME("(%p) : stub\n", This);
3058 if (NULL == pClipStatus) {
3059 return WINED3DERR_INVALIDCALL;
3061 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3062 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3066 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3068 FIXME("(%p) : stub\n", This);
3069 if (NULL == pClipStatus) {
3070 return WINED3DERR_INVALIDCALL;
3072 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3073 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3078 * Get / Set Material
3080 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3083 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3085 This->updateStateBlock->changed.material = TRUE;
3086 This->updateStateBlock->material = *pMaterial;
3088 /* Handle recording of state blocks */
3089 if (This->isRecordingState) {
3090 TRACE("Recording... not performing anything\n");
3094 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 *pMaterial = This->updateStateBlock->material;
3101 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3102 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3103 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3104 pMaterial->Ambient.b, pMaterial->Ambient.a);
3105 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3106 pMaterial->Specular.b, pMaterial->Specular.a);
3107 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3108 pMaterial->Emissive.b, pMaterial->Emissive.a);
3109 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3117 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3118 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3119 IWineD3DIndexBuffer *oldIdxs;
3121 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3122 oldIdxs = This->updateStateBlock->pIndexData;
3124 This->updateStateBlock->changed.indices = TRUE;
3125 This->updateStateBlock->pIndexData = pIndexData;
3127 /* Handle recording of state blocks */
3128 if (This->isRecordingState) {
3129 TRACE("Recording... not performing anything\n");
3130 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3131 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3135 if(oldIdxs != pIndexData) {
3136 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3137 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3138 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3143 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3144 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3146 *ppIndexData = This->stateBlock->pIndexData;
3148 /* up ref count on ppindexdata */
3150 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3151 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3153 TRACE("(%p) No index data set\n", This);
3155 TRACE("Returning %p\n", *ppIndexData);
3160 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3161 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3163 TRACE("(%p)->(%d)\n", This, BaseIndex);
3165 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3166 TRACE("Application is setting the old value over, nothing to do\n");
3170 This->updateStateBlock->baseVertexIndex = BaseIndex;
3172 if (This->isRecordingState) {
3173 TRACE("Recording... not performing anything\n");
3176 /* The base vertex index affects the stream sources */
3177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3183 TRACE("(%p) : base_index %p\n", This, base_index);
3185 *base_index = This->stateBlock->baseVertexIndex;
3187 TRACE("Returning %u\n", *base_index);
3193 * Get / Set Viewports
3195 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3196 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 TRACE("(%p)\n", This);
3199 This->updateStateBlock->changed.viewport = TRUE;
3200 This->updateStateBlock->viewport = *pViewport;
3202 /* Handle recording of state blocks */
3203 if (This->isRecordingState) {
3204 TRACE("Recording... not performing anything\n");
3208 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3209 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3216 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3218 TRACE("(%p)\n", This);
3219 *pViewport = This->stateBlock->viewport;
3224 * Get / Set Render States
3225 * TODO: Verify against dx9 definitions
3227 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3230 DWORD oldValue = This->stateBlock->renderState[State];
3232 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3234 This->updateStateBlock->changed.renderState[State] = TRUE;
3235 This->updateStateBlock->renderState[State] = Value;
3237 /* Handle recording of state blocks */
3238 if (This->isRecordingState) {
3239 TRACE("Recording... not performing anything\n");
3243 /* Compared here and not before the assignment to allow proper stateblock recording */
3244 if(Value == oldValue) {
3245 TRACE("Application is setting the old value over, nothing to do\n");
3247 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3253 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3256 *pValue = This->stateBlock->renderState[State];
3261 * Get / Set Sampler States
3262 * TODO: Verify against dx9 definitions
3265 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3269 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3270 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3272 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3273 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3276 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3277 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3278 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3281 * SetSampler is designed to allow for more than the standard up to 8 textures
3282 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3283 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3285 * http://developer.nvidia.com/object/General_FAQ.html#t6
3287 * There are two new settings for GForce
3289 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3290 * and the texture one:
3291 * GL_MAX_TEXTURE_COORDS_ARB.
3292 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3295 oldValue = This->stateBlock->samplerState[Sampler][Type];
3296 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3297 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3305 if(oldValue == Value) {
3306 TRACE("Application is setting the old value over, nothing to do\n");
3310 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3318 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3319 This, Sampler, debug_d3dsamplerstate(Type), Type);
3321 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3322 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3325 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3326 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3327 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3329 *Value = This->stateBlock->samplerState[Sampler][Type];
3330 TRACE("(%p) : Returning %#x\n", This, *Value);
3335 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 This->updateStateBlock->changed.scissorRect = TRUE;
3339 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3340 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3343 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3345 if(This->isRecordingState) {
3346 TRACE("Recording... not performing anything\n");
3350 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3355 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3358 *pRect = This->updateStateBlock->scissorRect;
3359 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3363 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3364 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3365 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3367 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3369 This->updateStateBlock->vertexDecl = pDecl;
3370 This->updateStateBlock->changed.vertexDecl = TRUE;
3372 if (This->isRecordingState) {
3373 TRACE("Recording... not performing anything\n");
3375 } else if(pDecl == oldDecl) {
3376 /* Checked after the assignment to allow proper stateblock recording */
3377 TRACE("Application is setting the old declaration over, nothing to do\n");
3381 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3385 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3386 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3388 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3390 *ppDecl = This->stateBlock->vertexDecl;
3391 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3395 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3396 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3397 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3399 This->updateStateBlock->vertexShader = pShader;
3400 This->updateStateBlock->changed.vertexShader = TRUE;
3402 if (This->isRecordingState) {
3403 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3404 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3405 TRACE("Recording... not performing anything\n");
3407 } else if(oldShader == pShader) {
3408 /* Checked here to allow proper stateblock recording */
3409 TRACE("App is setting the old shader over, nothing to do\n");
3413 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3414 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3415 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3417 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3422 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3423 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3425 if (NULL == ppShader) {
3426 return WINED3DERR_INVALIDCALL;
3428 *ppShader = This->stateBlock->vertexShader;
3429 if( NULL != *ppShader)
3430 IWineD3DVertexShader_AddRef(*ppShader);
3432 TRACE("(%p) : returning %p\n", This, *ppShader);
3436 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3437 IWineD3DDevice *iface,
3439 CONST BOOL *srcData,
3442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3443 int i, cnt = min(count, MAX_CONST_B - start);
3445 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3446 iface, srcData, start, count);
3448 if (srcData == NULL || cnt < 0)
3449 return WINED3DERR_INVALIDCALL;
3451 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3452 for (i = 0; i < cnt; i++)
3453 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3455 for (i = start; i < cnt + start; ++i) {
3456 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3459 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3464 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3465 IWineD3DDevice *iface,
3470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3471 int cnt = min(count, MAX_CONST_B - start);
3473 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3474 iface, dstData, start, count);
3476 if (dstData == NULL || cnt < 0)
3477 return WINED3DERR_INVALIDCALL;
3479 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3483 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3484 IWineD3DDevice *iface,
3489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 int i, cnt = min(count, MAX_CONST_I - start);
3492 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3493 iface, srcData, start, count);
3495 if (srcData == NULL || cnt < 0)
3496 return WINED3DERR_INVALIDCALL;
3498 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3499 for (i = 0; i < cnt; i++)
3500 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3501 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3503 for (i = start; i < cnt + start; ++i) {
3504 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3507 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3512 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3513 IWineD3DDevice *iface,
3518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3519 int cnt = min(count, MAX_CONST_I - start);
3521 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3522 iface, dstData, start, count);
3524 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3525 return WINED3DERR_INVALIDCALL;
3527 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3531 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3532 IWineD3DDevice *iface,
3534 CONST float *srcData,
3537 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3541 iface, srcData, start, count);
3543 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3544 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3545 return WINED3DERR_INVALIDCALL;
3547 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3549 for (i = 0; i < count; i++)
3550 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3551 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3554 for (i = start; i < count + start; ++i) {
3555 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3556 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3557 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3558 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3559 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3561 ptr->idx[ptr->count++] = i;
3562 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3571 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3572 IWineD3DDevice *iface,
3574 CONST float *srcData,
3577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3580 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3581 iface, srcData, start, count);
3583 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3584 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3585 return WINED3DERR_INVALIDCALL;
3587 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3589 for (i = 0; i < count; i++)
3590 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3591 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3594 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3595 * context. On a context switch the old context will be fully dirtified
3597 memset(This->activeContext->vshader_const_dirty + start, 1,
3598 sizeof(*This->activeContext->vshader_const_dirty) * count);
3599 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3606 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3607 IWineD3DDevice *iface,
3612 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3613 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3615 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3616 iface, dstData, start, count);
3618 if (dstData == NULL || cnt < 0)
3619 return WINED3DERR_INVALIDCALL;
3621 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3625 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3627 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3632 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3633 int i = This->rev_tex_unit_map[unit];
3634 int j = This->texUnitMap[stage];
3636 This->texUnitMap[stage] = unit;
3637 if (i != -1 && i != stage) {
3638 This->texUnitMap[i] = -1;
3641 This->rev_tex_unit_map[unit] = stage;
3642 if (j != -1 && j != unit) {
3643 This->rev_tex_unit_map[j] = -1;
3647 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3650 for (i = 0; i < MAX_TEXTURES; ++i) {
3651 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3652 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3653 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3654 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3655 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3656 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3657 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3658 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3660 if (color_op == WINED3DTOP_DISABLE) {
3661 /* Not used, and disable higher stages */
3662 while (i < MAX_TEXTURES) {
3663 This->fixed_function_usage_map[i] = FALSE;
3669 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3670 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3671 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3672 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3673 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3674 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3675 This->fixed_function_usage_map[i] = TRUE;
3677 This->fixed_function_usage_map[i] = FALSE;
3680 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3681 This->fixed_function_usage_map[i+1] = TRUE;
3686 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3689 device_update_fixed_function_usage_map(This);
3691 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3692 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3693 if (!This->fixed_function_usage_map[i]) continue;
3695 if (This->texUnitMap[i] != i) {
3696 device_map_stage(This, i, i);
3697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3698 markTextureStagesDirty(This, i);
3704 /* Now work out the mapping */
3706 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3707 if (!This->fixed_function_usage_map[i]) continue;
3709 if (This->texUnitMap[i] != tex) {
3710 device_map_stage(This, i, tex);
3711 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3712 markTextureStagesDirty(This, i);
3719 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3720 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3723 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3724 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3725 device_map_stage(This, i, i);
3726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3727 if (i < MAX_TEXTURES) {
3728 markTextureStagesDirty(This, i);
3734 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3735 int current_mapping = This->rev_tex_unit_map[unit];
3737 if (current_mapping == -1) {
3738 /* Not currently used */
3742 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3743 /* Used by a fragment sampler */
3745 if (!pshader_sampler_tokens) {
3746 /* No pixel shader, check fixed function */
3747 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3750 /* Pixel shader, check the shader's sampler map */
3751 return !pshader_sampler_tokens[current_mapping];
3754 /* Used by a vertex sampler */
3755 return !vshader_sampler_tokens[current_mapping];
3758 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3759 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3760 DWORD *pshader_sampler_tokens = NULL;
3761 int start = GL_LIMITS(combined_samplers) - 1;
3765 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3767 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3768 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3769 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3772 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3773 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3774 if (vshader_sampler_tokens[i]) {
3775 if (This->texUnitMap[vsampler_idx] != -1) {
3776 /* Already mapped somewhere */
3780 while (start >= 0) {
3781 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3782 device_map_stage(This, vsampler_idx, start);
3783 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3795 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3796 BOOL vs = use_vs(This);
3797 BOOL ps = use_ps(This);
3800 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3801 * that would be really messy and require shader recompilation
3802 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3803 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3806 device_map_psamplers(This);
3808 device_map_fixed_function_samplers(This);
3812 device_map_vsamplers(This, ps);
3816 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3818 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3819 This->updateStateBlock->pixelShader = pShader;
3820 This->updateStateBlock->changed.pixelShader = TRUE;
3822 /* Handle recording of state blocks */
3823 if (This->isRecordingState) {
3824 TRACE("Recording... not performing anything\n");
3827 if (This->isRecordingState) {
3828 TRACE("Recording... not performing anything\n");
3829 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3830 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3834 if(pShader == oldShader) {
3835 TRACE("App is setting the old pixel shader over, nothing to do\n");
3839 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3840 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3842 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3848 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3851 if (NULL == ppShader) {
3852 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3853 return WINED3DERR_INVALIDCALL;
3856 *ppShader = This->stateBlock->pixelShader;
3857 if (NULL != *ppShader) {
3858 IWineD3DPixelShader_AddRef(*ppShader);
3860 TRACE("(%p) : returning %p\n", This, *ppShader);
3864 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3865 IWineD3DDevice *iface,
3867 CONST BOOL *srcData,
3870 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3871 int i, cnt = min(count, MAX_CONST_B - start);
3873 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3874 iface, srcData, start, count);
3876 if (srcData == NULL || cnt < 0)
3877 return WINED3DERR_INVALIDCALL;
3879 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3880 for (i = 0; i < cnt; i++)
3881 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3883 for (i = start; i < cnt + start; ++i) {
3884 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3887 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3892 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3893 IWineD3DDevice *iface,
3898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3899 int cnt = min(count, MAX_CONST_B - start);
3901 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3902 iface, dstData, start, count);
3904 if (dstData == NULL || cnt < 0)
3905 return WINED3DERR_INVALIDCALL;
3907 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3911 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3912 IWineD3DDevice *iface,
3917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3918 int i, cnt = min(count, MAX_CONST_I - start);
3920 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3921 iface, srcData, start, count);
3923 if (srcData == NULL || cnt < 0)
3924 return WINED3DERR_INVALIDCALL;
3926 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3927 for (i = 0; i < cnt; i++)
3928 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3929 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3931 for (i = start; i < cnt + start; ++i) {
3932 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3940 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3941 IWineD3DDevice *iface,
3946 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3947 int cnt = min(count, MAX_CONST_I - start);
3949 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3950 iface, dstData, start, count);
3952 if (dstData == NULL || cnt < 0)
3953 return WINED3DERR_INVALIDCALL;
3955 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3959 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3960 IWineD3DDevice *iface,
3962 CONST float *srcData,
3965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3968 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3969 iface, srcData, start, count);
3971 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3972 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3973 return WINED3DERR_INVALIDCALL;
3975 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3977 for (i = 0; i < count; i++)
3978 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3979 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3982 for (i = start; i < count + start; ++i) {
3983 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3984 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3985 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3986 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3987 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3989 ptr->idx[ptr->count++] = i;
3990 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3994 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3999 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4000 IWineD3DDevice *iface,
4002 CONST float *srcData,
4005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4008 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4009 iface, srcData, start, count);
4011 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4012 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4013 return WINED3DERR_INVALIDCALL;
4015 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4017 for (i = 0; i < count; i++)
4018 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4019 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4022 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4023 * context. On a context switch the old context will be fully dirtified
4025 memset(This->activeContext->pshader_const_dirty + start, 1,
4026 sizeof(*This->activeContext->pshader_const_dirty) * count);
4027 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4029 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4034 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4035 IWineD3DDevice *iface,
4040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4041 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4043 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4044 iface, dstData, start, count);
4046 if (dstData == NULL || cnt < 0)
4047 return WINED3DERR_INVALIDCALL;
4049 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4053 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4055 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4056 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4058 DWORD DestFVF = dest->fvf;
4060 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4064 if (lpStrideData->u.s.normal.lpData) {
4065 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4068 if (lpStrideData->u.s.position.lpData == NULL) {
4069 ERR("Source has no position mask\n");
4070 return WINED3DERR_INVALIDCALL;
4073 /* We might access VBOs from this code, so hold the lock */
4076 if (dest->resource.allocatedMemory == NULL) {
4077 /* This may happen if we do direct locking into a vbo. Unlikely,
4078 * but theoretically possible(ddraw processvertices test)
4080 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4081 if(!dest->resource.allocatedMemory) {
4083 ERR("Out of memory\n");
4084 return E_OUTOFMEMORY;
4088 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4089 checkGLcall("glBindBufferARB");
4090 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4092 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4094 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4095 checkGLcall("glUnmapBufferARB");
4099 /* Get a pointer into the destination vbo(create one if none exists) and
4100 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4102 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4103 dest->Flags |= VBFLAG_CREATEVBO;
4104 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4108 unsigned char extrabytes = 0;
4109 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4110 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4111 * this may write 4 extra bytes beyond the area that should be written
4113 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4114 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4115 if(!dest_conv_addr) {
4116 ERR("Out of memory\n");
4117 /* Continue without storing converted vertices */
4119 dest_conv = dest_conv_addr;
4123 * a) WINED3DRS_CLIPPING is enabled
4124 * b) WINED3DVOP_CLIP is passed
4126 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4127 static BOOL warned = FALSE;
4129 * The clipping code is not quite correct. Some things need
4130 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4131 * so disable clipping for now.
4132 * (The graphics in Half-Life are broken, and my processvertices
4133 * test crashes with IDirect3DDevice3)
4139 FIXME("Clipping is broken and disabled for now\n");
4141 } else doClip = FALSE;
4142 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4144 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4147 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4148 WINED3DTS_PROJECTION,
4150 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4151 WINED3DTS_WORLDMATRIX(0),
4154 TRACE("View mat:\n");
4155 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);
4156 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);
4157 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);
4158 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);
4160 TRACE("Proj mat:\n");
4161 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);
4162 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);
4163 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);
4164 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);
4166 TRACE("World mat:\n");
4167 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);
4168 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);
4169 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);
4170 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);
4172 /* Get the viewport */
4173 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4174 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4175 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4177 multiply_matrix(&mat,&view_mat,&world_mat);
4178 multiply_matrix(&mat,&proj_mat,&mat);
4180 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4182 for (i = 0; i < dwCount; i+= 1) {
4183 unsigned int tex_index;
4185 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4186 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4187 /* The position first */
4189 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4191 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4193 /* Multiplication with world, view and projection matrix */
4194 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);
4195 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);
4196 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);
4197 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);
4199 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4201 /* WARNING: The following things are taken from d3d7 and were not yet checked
4202 * against d3d8 or d3d9!
4205 /* Clipping conditions: From msdn
4207 * A vertex is clipped if it does not match the following requirements
4211 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4213 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4214 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4219 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4220 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4223 /* "Normal" viewport transformation (not clipped)
4224 * 1) The values are divided by rhw
4225 * 2) The y axis is negative, so multiply it with -1
4226 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4227 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4228 * 4) Multiply x with Width/2 and add Width/2
4229 * 5) The same for the height
4230 * 6) Add the viewpoint X and Y to the 2D coordinates and
4231 * The minimum Z value to z
4232 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4234 * Well, basically it's simply a linear transformation into viewport
4246 z *= vp.MaxZ - vp.MinZ;
4248 x += vp.Width / 2 + vp.X;
4249 y += vp.Height / 2 + vp.Y;
4254 /* That vertex got clipped
4255 * Contrary to OpenGL it is not dropped completely, it just
4256 * undergoes a different calculation.
4258 TRACE("Vertex got clipped\n");
4265 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4266 * outside of the main vertex buffer memory. That needs some more
4271 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4274 ( (float *) dest_ptr)[0] = x;
4275 ( (float *) dest_ptr)[1] = y;
4276 ( (float *) dest_ptr)[2] = z;
4277 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4279 dest_ptr += 3 * sizeof(float);
4281 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4282 dest_ptr += sizeof(float);
4287 ( (float *) dest_conv)[0] = x * w;
4288 ( (float *) dest_conv)[1] = y * w;
4289 ( (float *) dest_conv)[2] = z * w;
4290 ( (float *) dest_conv)[3] = w;
4292 dest_conv += 3 * sizeof(float);
4294 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4295 dest_conv += sizeof(float);
4299 if (DestFVF & WINED3DFVF_PSIZE) {
4300 dest_ptr += sizeof(DWORD);
4301 if(dest_conv) dest_conv += sizeof(DWORD);
4303 if (DestFVF & WINED3DFVF_NORMAL) {
4305 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4306 /* AFAIK this should go into the lighting information */
4307 FIXME("Didn't expect the destination to have a normal\n");
4308 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4310 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4314 if (DestFVF & WINED3DFVF_DIFFUSE) {
4316 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4318 static BOOL warned = FALSE;
4321 ERR("No diffuse color in source, but destination has one\n");
4325 *( (DWORD *) dest_ptr) = 0xffffffff;
4326 dest_ptr += sizeof(DWORD);
4329 *( (DWORD *) dest_conv) = 0xffffffff;
4330 dest_conv += sizeof(DWORD);
4334 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4336 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4337 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4338 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4339 dest_conv += sizeof(DWORD);
4344 if (DestFVF & WINED3DFVF_SPECULAR) {
4345 /* What's the color value in the feedback buffer? */
4347 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4349 static BOOL warned = FALSE;
4352 ERR("No specular color in source, but destination has one\n");
4356 *( (DWORD *) dest_ptr) = 0xFF000000;
4357 dest_ptr += sizeof(DWORD);
4360 *( (DWORD *) dest_conv) = 0xFF000000;
4361 dest_conv += sizeof(DWORD);
4365 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4367 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4368 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4369 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4370 dest_conv += sizeof(DWORD);
4375 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4377 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4378 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4380 ERR("No source texture, but destination requests one\n");
4381 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4382 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4385 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4387 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4394 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4395 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4396 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4397 dwCount * get_flexible_vertex_size(DestFVF),
4399 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4400 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4407 #undef copy_and_next
4409 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4411 WineDirect3DVertexStridedData strided;
4412 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4413 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4416 ERR("Output vertex declaration not implemented yet\n");
4419 /* Need any context to write to the vbo. */
4420 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4422 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4423 * control the streamIsUP flag, thus restore it afterwards.
4425 This->stateBlock->streamIsUP = FALSE;
4426 memset(&strided, 0, sizeof(strided));
4427 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4428 This->stateBlock->streamIsUP = streamWasUP;
4430 if(vbo || SrcStartIndex) {
4432 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4433 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4435 * Also get the start index in, but only loop over all elements if there's something to add at all.
4437 #define FIXSRC(type) \
4438 if(strided.u.s.type.VBO) { \
4439 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4440 strided.u.s.type.VBO = 0; \
4441 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4443 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4447 if(strided.u.s.type.lpData) { \
4448 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4451 FIXSRC(blendWeights);
4452 FIXSRC(blendMatrixIndices);
4457 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4458 FIXSRC(texCoords[i]);
4471 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4475 * Get / Set Texture Stage States
4476 * TODO: Verify against dx9 definitions
4478 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4479 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4480 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4482 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4484 if (Stage >= MAX_TEXTURES) {
4485 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4489 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4490 This->updateStateBlock->textureState[Stage][Type] = Value;
4492 if (This->isRecordingState) {
4493 TRACE("Recording... not performing anything\n");
4497 /* Checked after the assignments to allow proper stateblock recording */
4498 if(oldValue == Value) {
4499 TRACE("App is setting the old value over, nothing to do\n");
4503 if(Stage > This->stateBlock->lowest_disabled_stage &&
4504 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4505 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4506 * Changes in other states are important on disabled stages too
4511 if(Type == WINED3DTSS_COLOROP) {
4514 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4515 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4516 * they have to be disabled
4518 * The current stage is dirtified below.
4520 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4521 TRACE("Additionally dirtifying stage %d\n", i);
4522 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4524 This->stateBlock->lowest_disabled_stage = Stage;
4525 TRACE("New lowest disabled: %d\n", Stage);
4526 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4527 /* Previously disabled stage enabled. Stages above it may need enabling
4528 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4529 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4531 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4534 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4535 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4538 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4539 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4541 This->stateBlock->lowest_disabled_stage = i;
4542 TRACE("New lowest disabled: %d\n", i);
4544 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4545 /* TODO: Built a stage -> texture unit mapping for register combiners */
4549 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4554 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4555 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4556 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4557 *pValue = This->updateStateBlock->textureState[Stage][Type];
4564 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4565 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4566 IWineD3DBaseTexture *oldTexture;
4568 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4570 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4571 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4574 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4575 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4576 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4579 oldTexture = This->updateStateBlock->textures[Stage];
4581 if(pTexture != NULL) {
4582 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4584 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4585 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4586 return WINED3DERR_INVALIDCALL;
4588 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4591 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4592 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4594 This->updateStateBlock->changed.textures[Stage] = TRUE;
4595 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4596 This->updateStateBlock->textures[Stage] = pTexture;
4598 /* Handle recording of state blocks */
4599 if (This->isRecordingState) {
4600 TRACE("Recording... not performing anything\n");
4604 if(oldTexture == pTexture) {
4605 TRACE("App is setting the same texture again, nothing to do\n");
4609 /** NOTE: MSDN says that setTexture increases the reference count,
4610 * and that the application must set the texture back to null (or have a leaky application),
4611 * This means we should pass the refcount up to the parent
4612 *******************************/
4613 if (NULL != This->updateStateBlock->textures[Stage]) {
4614 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4615 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4617 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4618 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4619 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4620 * so the COLOROP and ALPHAOP have to be dirtified.
4622 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4625 if(bindCount == 1) {
4626 new->baseTexture.sampler = Stage;
4628 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4632 if (NULL != oldTexture) {
4633 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4634 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4636 IWineD3DBaseTexture_Release(oldTexture);
4637 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4638 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4639 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4642 if(bindCount && old->baseTexture.sampler == Stage) {
4644 /* Have to do a search for the other sampler(s) where the texture is bound to
4645 * Shouldn't happen as long as apps bind a texture only to one stage
4647 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4648 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4649 if(This->updateStateBlock->textures[i] == oldTexture) {
4650 old->baseTexture.sampler = i;
4657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4662 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4665 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4667 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4668 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4671 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4672 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4673 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4676 *ppTexture=This->stateBlock->textures[Stage];
4678 IWineD3DBaseTexture_AddRef(*ppTexture);
4680 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4688 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4689 IWineD3DSurface **ppBackBuffer) {
4690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4691 IWineD3DSwapChain *swapChain;
4694 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4696 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4697 if (hr == WINED3D_OK) {
4698 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4699 IWineD3DSwapChain_Release(swapChain);
4701 *ppBackBuffer = NULL;
4706 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4708 WARN("(%p) : stub, calling idirect3d for now\n", This);
4709 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4712 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4714 IWineD3DSwapChain *swapChain;
4717 if(iSwapChain > 0) {
4718 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4719 if (hr == WINED3D_OK) {
4720 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4721 IWineD3DSwapChain_Release(swapChain);
4723 FIXME("(%p) Error getting display mode\n", This);
4726 /* Don't read the real display mode,
4727 but return the stored mode instead. X11 can't change the color
4728 depth, and some apps are pretty angry if they SetDisplayMode from
4729 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4731 Also don't relay to the swapchain because with ddraw it's possible
4732 that there isn't a swapchain at all */
4733 pMode->Width = This->ddraw_width;
4734 pMode->Height = This->ddraw_height;
4735 pMode->Format = This->ddraw_format;
4736 pMode->RefreshRate = 0;
4743 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4744 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4745 TRACE("(%p)->(%p)\n", This, hWnd);
4747 if(This->ddraw_fullscreen) {
4748 if(This->ddraw_window && This->ddraw_window != hWnd) {
4749 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4751 if(hWnd && This->ddraw_window != hWnd) {
4752 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4756 This->ddraw_window = hWnd;
4760 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4761 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4762 TRACE("(%p)->(%p)\n", This, hWnd);
4764 *hWnd = This->ddraw_window;
4769 * Stateblock related functions
4772 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4774 IWineD3DStateBlockImpl *object;
4775 HRESULT temp_result;
4778 TRACE("(%p)\n", This);
4780 if (This->isRecordingState) {
4781 return WINED3DERR_INVALIDCALL;
4784 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4785 if (NULL == object ) {
4786 FIXME("(%p)Error allocating memory for stateblock\n", This);
4787 return E_OUTOFMEMORY;
4789 TRACE("(%p) created object %p\n", This, object);
4790 object->wineD3DDevice= This;
4791 /** FIXME: object->parent = parent; **/
4792 object->parent = NULL;
4793 object->blockType = WINED3DSBT_RECORDED;
4795 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4797 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4798 list_init(&object->lightMap[i]);
4801 temp_result = allocate_shader_constants(object);
4802 if (WINED3D_OK != temp_result)
4805 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4806 This->updateStateBlock = object;
4807 This->isRecordingState = TRUE;
4809 TRACE("(%p) recording stateblock %p\n",This , object);
4813 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4814 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4816 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4818 if (!This->isRecordingState) {
4819 FIXME("(%p) not recording! returning error\n", This);
4820 *ppStateBlock = NULL;
4821 return WINED3DERR_INVALIDCALL;
4824 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4825 if(object->changed.renderState[i]) {
4826 object->contained_render_states[object->num_contained_render_states] = i;
4827 object->num_contained_render_states++;
4830 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4831 if(object->changed.transform[i]) {
4832 object->contained_transform_states[object->num_contained_transform_states] = i;
4833 object->num_contained_transform_states++;
4836 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4837 if(object->changed.vertexShaderConstantsF[i]) {
4838 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4839 object->num_contained_vs_consts_f++;
4842 for(i = 0; i < MAX_CONST_I; i++) {
4843 if(object->changed.vertexShaderConstantsI[i]) {
4844 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4845 object->num_contained_vs_consts_i++;
4848 for(i = 0; i < MAX_CONST_B; i++) {
4849 if(object->changed.vertexShaderConstantsB[i]) {
4850 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4851 object->num_contained_vs_consts_b++;
4854 for(i = 0; i < MAX_CONST_I; i++) {
4855 if(object->changed.pixelShaderConstantsI[i]) {
4856 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4857 object->num_contained_ps_consts_i++;
4860 for(i = 0; i < MAX_CONST_B; i++) {
4861 if(object->changed.pixelShaderConstantsB[i]) {
4862 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4863 object->num_contained_ps_consts_b++;
4866 for(i = 0; i < MAX_TEXTURES; i++) {
4867 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4868 if(object->changed.textureState[i][j]) {
4869 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4870 object->contained_tss_states[object->num_contained_tss_states].state = j;
4871 object->num_contained_tss_states++;
4875 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4876 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4877 if(object->changed.samplerState[i][j]) {
4878 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4879 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4880 object->num_contained_sampler_states++;
4885 *ppStateBlock = (IWineD3DStateBlock*) object;
4886 This->isRecordingState = FALSE;
4887 This->updateStateBlock = This->stateBlock;
4888 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4889 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4890 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4895 * Scene related functions
4897 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4898 /* At the moment we have no need for any functionality at the beginning
4900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4901 TRACE("(%p)\n", This);
4904 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4905 return WINED3DERR_INVALIDCALL;
4907 This->inScene = TRUE;
4911 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4913 TRACE("(%p)\n", This);
4915 if(!This->inScene) {
4916 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4917 return WINED3DERR_INVALIDCALL;
4920 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4921 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4924 checkGLcall("glFlush");
4927 This->inScene = FALSE;
4931 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4932 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4933 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4935 IWineD3DSwapChain *swapChain = NULL;
4937 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4939 TRACE("(%p) Presenting the frame\n", This);
4941 for(i = 0 ; i < swapchains ; i ++) {
4943 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4944 TRACE("presentinng chain %d, %p\n", i, swapChain);
4945 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4946 IWineD3DSwapChain_Release(swapChain);
4952 /* Not called from the VTable (internal subroutine) */
4953 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4954 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4955 float Z, DWORD Stencil) {
4956 GLbitfield glMask = 0;
4958 WINED3DRECT curRect;
4960 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4961 UINT drawable_width, drawable_height;
4962 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4964 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4965 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4966 * for the cleared parts, and the untouched parts.
4968 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4969 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4970 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4971 * checking all this if the dest surface is in the drawable anyway.
4973 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4975 if(vp->X != 0 || vp->Y != 0 ||
4976 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4977 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4980 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4981 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4982 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4983 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4984 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4987 if(Count > 0 && pRects && (
4988 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4989 pRects[0].x2 < target->currentDesc.Width ||
4990 pRects[0].y2 < target->currentDesc.Height)) {
4991 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4998 target->get_drawable_size(target, &drawable_width, &drawable_height);
5000 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5003 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5004 apply_fbo_state((IWineD3DDevice *) This);
5007 /* Only set the values up once, as they are not changing */
5008 if (Flags & WINED3DCLEAR_STENCIL) {
5009 glClearStencil(Stencil);
5010 checkGLcall("glClearStencil");
5011 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5012 glStencilMask(0xFFFFFFFF);
5015 if (Flags & WINED3DCLEAR_ZBUFFER) {
5016 glDepthMask(GL_TRUE);
5018 checkGLcall("glClearDepth");
5019 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5020 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5022 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5023 if(vp->X != 0 || vp->Y != 0 ||
5024 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5025 depth_copy((IWineD3DDevice *) This);
5027 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5028 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5029 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5030 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5031 depth_copy((IWineD3DDevice *) This);
5033 else if(Count > 0 && pRects && (
5034 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5035 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5036 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5037 depth_copy((IWineD3DDevice *) This);
5040 This->depth_copy_state = WINED3D_DCS_INITIAL;
5043 if (Flags & WINED3DCLEAR_TARGET) {
5044 TRACE("Clearing screen with glClear to color %x\n", Color);
5045 glClearColor(D3DCOLOR_R(Color),
5049 checkGLcall("glClearColor");
5051 /* Clear ALL colors! */
5052 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5053 glMask = glMask | GL_COLOR_BUFFER_BIT;
5056 vp_rect.left = vp->X;
5057 vp_rect.top = vp->Y;
5058 vp_rect.right = vp->X + vp->Width;
5059 vp_rect.bottom = vp->Y + vp->Height;
5060 if (!(Count > 0 && pRects)) {
5061 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5062 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5064 if(This->render_offscreen) {
5065 glScissor(vp_rect.left, vp_rect.top,
5066 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5068 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5069 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5071 checkGLcall("glScissor");
5073 checkGLcall("glClear");
5075 /* Now process each rect in turn */
5076 for (i = 0; i < Count; i++) {
5077 /* Note gl uses lower left, width/height */
5078 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5079 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5080 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5082 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5083 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5084 curRect.x1, (target->currentDesc.Height - curRect.y2),
5085 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5087 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5088 * The rectangle is not cleared, no error is returned, but further rectanlges are
5089 * still cleared if they are valid
5091 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5092 TRACE("Rectangle with negative dimensions, ignoring\n");
5096 if(This->render_offscreen) {
5097 glScissor(curRect.x1, curRect.y1,
5098 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5100 glScissor(curRect.x1, drawable_height - curRect.y2,
5101 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5103 checkGLcall("glScissor");
5106 checkGLcall("glClear");
5110 /* Restore the old values (why..?) */
5111 if (Flags & WINED3DCLEAR_STENCIL) {
5112 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5114 if (Flags & WINED3DCLEAR_TARGET) {
5115 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5116 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5117 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5118 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5119 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5121 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5122 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5124 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5125 /* TODO: Move the fbo logic into ModifyLocation() */
5126 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5127 target->Flags |= SFLAG_INTEXTURE;
5135 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5136 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5138 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5140 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5141 Count, pRects, Flags, Color, Z, Stencil);
5143 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5144 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5145 /* TODO: What about depth stencil buffers without stencil bits? */
5146 return WINED3DERR_INVALIDCALL;
5149 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5155 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5156 UINT PrimitiveCount) {
5158 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5160 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5161 debug_d3dprimitivetype(PrimitiveType),
5162 StartVertex, PrimitiveCount);
5164 if(!This->stateBlock->vertexDecl) {
5165 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5166 return WINED3DERR_INVALIDCALL;
5169 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5170 if(This->stateBlock->streamIsUP) {
5171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5172 This->stateBlock->streamIsUP = FALSE;
5175 if(This->stateBlock->loadBaseVertexIndex != 0) {
5176 This->stateBlock->loadBaseVertexIndex = 0;
5177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5179 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5180 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5181 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5185 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5186 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5187 WINED3DPRIMITIVETYPE PrimitiveType,
5188 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5190 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5192 IWineD3DIndexBuffer *pIB;
5193 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5196 pIB = This->stateBlock->pIndexData;
5198 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5199 * without an index buffer set. (The first time at least...)
5200 * D3D8 simply dies, but I doubt it can do much harm to return
5201 * D3DERR_INVALIDCALL there as well. */
5202 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5203 return WINED3DERR_INVALIDCALL;
5206 if(!This->stateBlock->vertexDecl) {
5207 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5208 return WINED3DERR_INVALIDCALL;
5211 if(This->stateBlock->streamIsUP) {
5212 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5213 This->stateBlock->streamIsUP = FALSE;
5215 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5217 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5218 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5219 minIndex, NumVertices, startIndex, primCount);
5221 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5222 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5228 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5229 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5233 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5234 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5239 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5240 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5241 UINT VertexStreamZeroStride) {
5242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5243 IWineD3DVertexBuffer *vb;
5245 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5246 debug_d3dprimitivetype(PrimitiveType),
5247 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5249 if(!This->stateBlock->vertexDecl) {
5250 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5251 return WINED3DERR_INVALIDCALL;
5254 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5255 vb = This->stateBlock->streamSource[0];
5256 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5257 if(vb) IWineD3DVertexBuffer_Release(vb);
5258 This->stateBlock->streamOffset[0] = 0;
5259 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5260 This->stateBlock->streamIsUP = TRUE;
5261 This->stateBlock->loadBaseVertexIndex = 0;
5263 /* TODO: Only mark dirty if drawing from a different UP address */
5264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5266 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5267 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5269 /* MSDN specifies stream zero settings must be set to NULL */
5270 This->stateBlock->streamStride[0] = 0;
5271 This->stateBlock->streamSource[0] = NULL;
5273 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5274 * the new stream sources or use UP drawing again
5279 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5280 UINT MinVertexIndex, UINT NumVertices,
5281 UINT PrimitiveCount, CONST void* pIndexData,
5282 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5283 UINT VertexStreamZeroStride) {
5285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5286 IWineD3DVertexBuffer *vb;
5287 IWineD3DIndexBuffer *ib;
5289 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5290 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5291 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5292 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5294 if(!This->stateBlock->vertexDecl) {
5295 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5296 return WINED3DERR_INVALIDCALL;
5299 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5305 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5306 vb = This->stateBlock->streamSource[0];
5307 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5308 if(vb) IWineD3DVertexBuffer_Release(vb);
5309 This->stateBlock->streamIsUP = TRUE;
5310 This->stateBlock->streamOffset[0] = 0;
5311 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5313 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5314 This->stateBlock->baseVertexIndex = 0;
5315 This->stateBlock->loadBaseVertexIndex = 0;
5316 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5317 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5320 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5322 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5323 This->stateBlock->streamSource[0] = NULL;
5324 This->stateBlock->streamStride[0] = 0;
5325 ib = This->stateBlock->pIndexData;
5327 IWineD3DIndexBuffer_Release(ib);
5328 This->stateBlock->pIndexData = NULL;
5330 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5331 * SetStreamSource to specify a vertex buffer
5337 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5340 /* Mark the state dirty until we have nicer tracking
5341 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5344 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5345 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5346 This->stateBlock->baseVertexIndex = 0;
5347 This->up_strided = DrawPrimStrideData;
5348 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5349 This->up_strided = NULL;
5353 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5355 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5357 /* Mark the state dirty until we have nicer tracking
5358 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5363 This->stateBlock->streamIsUP = TRUE;
5364 This->stateBlock->baseVertexIndex = 0;
5365 This->up_strided = DrawPrimStrideData;
5366 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5367 This->up_strided = NULL;
5371 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5372 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5373 * not callable by the app directly no parameter validation checks are needed here.
5375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5376 WINED3DLOCKED_BOX src;
5377 WINED3DLOCKED_BOX dst;
5379 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5381 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5382 * dirtification to improve loading performance.
5384 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5385 if(FAILED(hr)) return hr;
5386 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5388 IWineD3DVolume_UnlockBox(pSourceVolume);
5392 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5394 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5396 IWineD3DVolume_UnlockBox(pSourceVolume);
5398 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5403 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5404 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5406 HRESULT hr = WINED3D_OK;
5407 WINED3DRESOURCETYPE sourceType;
5408 WINED3DRESOURCETYPE destinationType;
5411 /* TODO: think about moving the code into IWineD3DBaseTexture */
5413 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5415 /* verify that the source and destination textures aren't NULL */
5416 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5417 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5418 This, pSourceTexture, pDestinationTexture);
5419 hr = WINED3DERR_INVALIDCALL;
5422 if (pSourceTexture == pDestinationTexture) {
5423 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5424 This, pSourceTexture, pDestinationTexture);
5425 hr = WINED3DERR_INVALIDCALL;
5427 /* Verify that the source and destination textures are the same type */
5428 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5429 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5431 if (sourceType != destinationType) {
5432 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5434 hr = WINED3DERR_INVALIDCALL;
5437 /* check that both textures have the identical numbers of levels */
5438 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5439 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5440 hr = WINED3DERR_INVALIDCALL;
5443 if (WINED3D_OK == hr) {
5445 /* Make sure that the destination texture is loaded */
5446 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5448 /* Update every surface level of the texture */
5449 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5451 switch (sourceType) {
5452 case WINED3DRTYPE_TEXTURE:
5454 IWineD3DSurface *srcSurface;
5455 IWineD3DSurface *destSurface;
5457 for (i = 0 ; i < levels ; ++i) {
5458 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5459 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5460 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5461 IWineD3DSurface_Release(srcSurface);
5462 IWineD3DSurface_Release(destSurface);
5463 if (WINED3D_OK != hr) {
5464 WARN("(%p) : Call to update surface failed\n", This);
5470 case WINED3DRTYPE_CUBETEXTURE:
5472 IWineD3DSurface *srcSurface;
5473 IWineD3DSurface *destSurface;
5474 WINED3DCUBEMAP_FACES faceType;
5476 for (i = 0 ; i < levels ; ++i) {
5477 /* Update each cube face */
5478 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5479 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5480 if (WINED3D_OK != hr) {
5481 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5483 TRACE("Got srcSurface %p\n", srcSurface);
5485 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5486 if (WINED3D_OK != hr) {
5487 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5489 TRACE("Got desrSurface %p\n", destSurface);
5491 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5492 IWineD3DSurface_Release(srcSurface);
5493 IWineD3DSurface_Release(destSurface);
5494 if (WINED3D_OK != hr) {
5495 WARN("(%p) : Call to update surface failed\n", This);
5503 case WINED3DRTYPE_VOLUMETEXTURE:
5505 IWineD3DVolume *srcVolume = NULL;
5506 IWineD3DVolume *destVolume = NULL;
5508 for (i = 0 ; i < levels ; ++i) {
5509 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5510 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5511 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5512 IWineD3DVolume_Release(srcVolume);
5513 IWineD3DVolume_Release(destVolume);
5514 if (WINED3D_OK != hr) {
5515 WARN("(%p) : Call to update volume failed\n", This);
5523 FIXME("(%p) : Unsupported source and destination type\n", This);
5524 hr = WINED3DERR_INVALIDCALL;
5531 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5532 IWineD3DSwapChain *swapChain;
5534 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5535 if(hr == WINED3D_OK) {
5536 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5537 IWineD3DSwapChain_Release(swapChain);
5542 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5544 /* return a sensible default */
5546 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5547 FIXME("(%p) : stub\n", This);
5551 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5555 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5556 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5557 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5558 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5563 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5567 PALETTEENTRY **palettes;
5569 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5571 if (PaletteNumber >= MAX_PALETTES) {
5572 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5573 return WINED3DERR_INVALIDCALL;
5576 if (PaletteNumber >= This->NumberOfPalettes) {
5577 NewSize = This->NumberOfPalettes;
5580 } while(PaletteNumber >= NewSize);
5581 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5583 ERR("Out of memory!\n");
5584 return E_OUTOFMEMORY;
5586 This->palettes = palettes;
5587 This->NumberOfPalettes = NewSize;
5590 if (!This->palettes[PaletteNumber]) {
5591 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5592 if (!This->palettes[PaletteNumber]) {
5593 ERR("Out of memory!\n");
5594 return E_OUTOFMEMORY;
5598 for (j = 0; j < 256; ++j) {
5599 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5600 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5601 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5602 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5604 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5605 TRACE("(%p) : returning\n", This);
5609 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5612 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5613 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5614 /* What happens in such situation isn't documented; Native seems to silently abort
5615 on such conditions. Return Invalid Call. */
5616 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5617 return WINED3DERR_INVALIDCALL;
5619 for (j = 0; j < 256; ++j) {
5620 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5621 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5622 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5623 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5625 TRACE("(%p) : returning\n", This);
5629 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5630 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5631 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5632 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5633 (tested with reference rasterizer). Return Invalid Call. */
5634 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5635 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5636 return WINED3DERR_INVALIDCALL;
5638 /*TODO: stateblocks */
5639 if (This->currentPalette != PaletteNumber) {
5640 This->currentPalette = PaletteNumber;
5641 dirtify_p8_texture_samplers(This);
5643 TRACE("(%p) : returning\n", This);
5647 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5649 if (PaletteNumber == NULL) {
5650 WARN("(%p) : returning Invalid Call\n", This);
5651 return WINED3DERR_INVALIDCALL;
5653 /*TODO: stateblocks */
5654 *PaletteNumber = This->currentPalette;
5655 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5659 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5661 static BOOL showFixmes = TRUE;
5663 FIXME("(%p) : stub\n", This);
5667 This->softwareVertexProcessing = bSoftware;
5672 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5674 static BOOL showFixmes = TRUE;
5676 FIXME("(%p) : stub\n", This);
5679 return This->softwareVertexProcessing;
5683 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 IWineD3DSwapChain *swapChain;
5688 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5690 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5691 if(hr == WINED3D_OK){
5692 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5693 IWineD3DSwapChain_Release(swapChain);
5695 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5701 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 static BOOL showfixmes = TRUE;
5704 if(nSegments != 0.0f) {
5706 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5713 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 static BOOL showfixmes = TRUE;
5717 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5723 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5724 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5725 /** TODO: remove casts to IWineD3DSurfaceImpl
5726 * NOTE: move code to surface to accomplish this
5727 ****************************************/
5728 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5729 int srcWidth, srcHeight;
5730 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5731 WINED3DFORMAT destFormat, srcFormat;
5733 int srcLeft, destLeft, destTop;
5734 WINED3DPOOL srcPool, destPool;
5736 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5737 glDescriptor *glDescription = NULL;
5740 CONVERT_TYPES convert = NO_CONVERSION;
5742 WINED3DSURFACE_DESC winedesc;
5744 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5745 memset(&winedesc, 0, sizeof(winedesc));
5746 winedesc.Width = &srcSurfaceWidth;
5747 winedesc.Height = &srcSurfaceHeight;
5748 winedesc.Pool = &srcPool;
5749 winedesc.Format = &srcFormat;
5751 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5753 winedesc.Width = &destSurfaceWidth;
5754 winedesc.Height = &destSurfaceHeight;
5755 winedesc.Pool = &destPool;
5756 winedesc.Format = &destFormat;
5757 winedesc.Size = &destSize;
5759 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5761 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5762 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5763 return WINED3DERR_INVALIDCALL;
5766 /* This call loads the opengl surface directly, instead of copying the surface to the
5767 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5768 * copy in sysmem and use regular surface loading.
5770 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5771 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5772 if(convert != NO_CONVERSION) {
5773 return IWineD3DSurface_BltFast(pDestinationSurface,
5774 pDestPoint ? pDestPoint->x : 0,
5775 pDestPoint ? pDestPoint->y : 0,
5776 pSourceSurface, (RECT *) pSourceRect, 0);
5779 if (destFormat == WINED3DFMT_UNKNOWN) {
5780 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5781 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5783 /* Get the update surface description */
5784 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5787 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5791 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5792 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5793 checkGLcall("glActiveTextureARB");
5796 /* Make sure the surface is loaded and up to date */
5797 IWineD3DSurface_PreLoad(pDestinationSurface);
5799 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5801 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5802 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5803 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5804 srcLeft = pSourceRect ? pSourceRect->left : 0;
5805 destLeft = pDestPoint ? pDestPoint->x : 0;
5806 destTop = pDestPoint ? pDestPoint->y : 0;
5809 /* This function doesn't support compressed textures
5810 the pitch is just bytesPerPixel * width */
5811 if(srcWidth != srcSurfaceWidth || srcLeft ){
5812 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5813 offset += srcLeft * pSrcSurface->bytesPerPixel;
5814 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5816 /* TODO DXT formats */
5818 if(pSourceRect != NULL && pSourceRect->top != 0){
5819 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5821 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5823 ,glDescription->level
5828 ,glDescription->glFormat
5829 ,glDescription->glType
5830 ,IWineD3DSurface_GetData(pSourceSurface)
5834 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5836 /* need to lock the surface to get the data */
5837 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5840 /* TODO: Cube and volume support */
5842 /* not a whole row so we have to do it a line at a time */
5845 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5846 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5848 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5850 glTexSubImage2D(glDescription->target
5851 ,glDescription->level
5856 ,glDescription->glFormat
5857 ,glDescription->glType
5858 ,data /* could be quicker using */
5863 } else { /* Full width, so just write out the whole texture */
5865 if (WINED3DFMT_DXT1 == destFormat ||
5866 WINED3DFMT_DXT2 == destFormat ||
5867 WINED3DFMT_DXT3 == destFormat ||
5868 WINED3DFMT_DXT4 == destFormat ||
5869 WINED3DFMT_DXT5 == destFormat) {
5870 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5871 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5872 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5873 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5874 } if (destFormat != srcFormat) {
5875 FIXME("Updating mixed format compressed texture is not curretly support\n");
5877 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5878 glDescription->level,
5879 glDescription->glFormatInternal,
5884 IWineD3DSurface_GetData(pSourceSurface));
5887 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5892 glTexSubImage2D(glDescription->target
5893 ,glDescription->level
5898 ,glDescription->glFormat
5899 ,glDescription->glType
5900 ,IWineD3DSurface_GetData(pSourceSurface)
5904 checkGLcall("glTexSubImage2D");
5908 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5914 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5916 struct WineD3DRectPatch *patch;
5920 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5922 if(!(Handle || pRectPatchInfo)) {
5923 /* TODO: Write a test for the return value, thus the FIXME */
5924 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5925 return WINED3DERR_INVALIDCALL;
5929 i = PATCHMAP_HASHFUNC(Handle);
5931 LIST_FOR_EACH(e, &This->patches[i]) {
5932 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5933 if(patch->Handle == Handle) {
5940 TRACE("Patch does not exist. Creating a new one\n");
5941 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5942 patch->Handle = Handle;
5943 list_add_head(&This->patches[i], &patch->entry);
5945 TRACE("Found existing patch %p\n", patch);
5948 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5949 * attributes we have to tesselate, read back, and draw. This needs a patch
5950 * management structure instance. Create one.
5952 * A possible improvement is to check if a vertex shader is used, and if not directly
5955 FIXME("Drawing an uncached patch. This is slow\n");
5956 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5959 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5960 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5961 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5963 TRACE("Tesselation density or patch info changed, retesselating\n");
5965 if(pRectPatchInfo) {
5966 patch->RectPatchInfo = *pRectPatchInfo;
5968 patch->numSegs[0] = pNumSegs[0];
5969 patch->numSegs[1] = pNumSegs[1];
5970 patch->numSegs[2] = pNumSegs[2];
5971 patch->numSegs[3] = pNumSegs[3];
5973 hr = tesselate_rectpatch(This, patch);
5975 WARN("Patch tesselation failed\n");
5977 /* Do not release the handle to store the params of the patch */
5979 HeapFree(GetProcessHeap(), 0, patch);
5985 This->currentPatch = patch;
5986 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5987 This->currentPatch = NULL;
5989 /* Destroy uncached patches */
5991 HeapFree(GetProcessHeap(), 0, patch->mem);
5992 HeapFree(GetProcessHeap(), 0, patch);
5997 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5999 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6000 FIXME("(%p) : Stub\n", This);
6004 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6007 struct WineD3DRectPatch *patch;
6009 TRACE("(%p) Handle(%d)\n", This, Handle);
6011 i = PATCHMAP_HASHFUNC(Handle);
6012 LIST_FOR_EACH(e, &This->patches[i]) {
6013 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6014 if(patch->Handle == Handle) {
6015 TRACE("Deleting patch %p\n", patch);
6016 list_remove(&patch->entry);
6017 HeapFree(GetProcessHeap(), 0, patch->mem);
6018 HeapFree(GetProcessHeap(), 0, patch);
6023 /* TODO: Write a test for the return value */
6024 FIXME("Attempt to destroy nonexistent patch\n");
6025 return WINED3DERR_INVALIDCALL;
6028 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6030 IWineD3DSwapChain *swapchain;
6032 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6033 if (SUCCEEDED(hr)) {
6034 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6041 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6045 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6046 checkGLcall("glGenFramebuffersEXT()");
6048 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6049 checkGLcall("glBindFramebuffer()");
6052 /* TODO: Handle stencil attachments */
6053 static void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6054 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6056 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6057 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6058 checkGLcall("glFramebufferRenderbufferEXT()");
6060 IWineD3DBaseTextureImpl *texture_impl;
6061 GLenum texttarget, target;
6062 GLint old_binding = 0;
6064 texttarget = depth_stencil_impl->glDescription.target;
6065 if(texttarget == GL_TEXTURE_2D) {
6066 target = GL_TEXTURE_2D;
6067 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6068 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6069 target = GL_TEXTURE_RECTANGLE_ARB;
6070 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6072 target = GL_TEXTURE_CUBE_MAP_ARB;
6073 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6076 IWineD3DSurface_PreLoad(depth_stencil);
6078 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6079 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6080 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6081 glBindTexture(target, old_binding);
6083 /* Update base texture states array */
6084 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6085 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6086 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6087 if (texture_impl->baseTexture.bindCount) {
6088 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6091 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6094 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6095 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6096 checkGLcall("glFramebufferTexture2DEXT()");
6100 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6101 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6102 IWineD3DBaseTextureImpl *texture_impl;
6103 GLenum texttarget, target;
6106 texttarget = surface_impl->glDescription.target;
6107 if(texttarget == GL_TEXTURE_2D) {
6108 target = GL_TEXTURE_2D;
6109 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6110 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6111 target = GL_TEXTURE_RECTANGLE_ARB;
6112 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6114 target = GL_TEXTURE_CUBE_MAP_ARB;
6115 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6118 IWineD3DSurface_PreLoad(surface);
6120 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6121 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6122 glBindTexture(target, old_binding);
6124 /* Update base texture states array */
6125 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6126 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6127 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6128 if (texture_impl->baseTexture.bindCount) {
6129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6132 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6135 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6136 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6138 checkGLcall("attach_surface_fbo");
6141 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6142 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6143 IWineD3DSwapChain *swapchain;
6145 swapchain = get_swapchain(surface);
6149 TRACE("Surface %p is onscreen\n", surface);
6151 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6152 buffer = surface_get_gl_buffer(surface, swapchain);
6153 glDrawBuffer(buffer);
6154 checkGLcall("glDrawBuffer()");
6156 TRACE("Surface %p is offscreen\n", surface);
6157 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6158 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6159 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6160 checkGLcall("glFramebufferRenderbufferEXT");
6164 glEnable(GL_SCISSOR_TEST);
6166 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6168 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6169 rect->x2 - rect->x1, rect->y2 - rect->y1);
6171 checkGLcall("glScissor");
6173 glDisable(GL_SCISSOR_TEST);
6175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6177 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6178 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6180 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6181 glClear(GL_COLOR_BUFFER_BIT);
6182 checkGLcall("glClear");
6184 if (This->render_offscreen) {
6185 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6187 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6188 checkGLcall("glBindFramebuffer()");
6191 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6192 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6193 glDrawBuffer(GL_BACK);
6194 checkGLcall("glDrawBuffer()");
6198 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6199 unsigned int r, g, b, a;
6202 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6203 destfmt == WINED3DFMT_R8G8B8)
6206 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6208 a = (color & 0xff000000) >> 24;
6209 r = (color & 0x00ff0000) >> 16;
6210 g = (color & 0x0000ff00) >> 8;
6211 b = (color & 0x000000ff) >> 0;
6215 case WINED3DFMT_R5G6B5:
6216 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6223 TRACE("Returning %08x\n", ret);
6226 case WINED3DFMT_X1R5G5B5:
6227 case WINED3DFMT_A1R5G5B5:
6236 TRACE("Returning %08x\n", ret);
6240 TRACE("Returning %08x\n", a);
6243 case WINED3DFMT_X4R4G4B4:
6244 case WINED3DFMT_A4R4G4B4:
6253 TRACE("Returning %08x\n", ret);
6256 case WINED3DFMT_R3G3B2:
6263 TRACE("Returning %08x\n", ret);
6266 case WINED3DFMT_X8B8G8R8:
6267 case WINED3DFMT_A8B8G8R8:
6272 TRACE("Returning %08x\n", ret);
6275 case WINED3DFMT_A2R10G10B10:
6277 r = (r * 1024) / 256;
6278 g = (g * 1024) / 256;
6279 b = (b * 1024) / 256;
6284 TRACE("Returning %08x\n", ret);
6287 case WINED3DFMT_A2B10G10R10:
6289 r = (r * 1024) / 256;
6290 g = (g * 1024) / 256;
6291 b = (b * 1024) / 256;
6296 TRACE("Returning %08x\n", ret);
6300 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6305 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6307 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6309 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6311 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6312 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6313 return WINED3DERR_INVALIDCALL;
6316 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6318 color_fill_fbo(iface, pSurface, pRect, color);
6322 /* Just forward this to the DirectDraw blitting engine */
6323 memset(&BltFx, 0, sizeof(BltFx));
6324 BltFx.dwSize = sizeof(BltFx);
6325 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6326 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6330 /* rendertarget and depth stencil functions */
6331 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6334 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6335 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6336 return WINED3DERR_INVALIDCALL;
6339 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6340 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6341 /* Note inc ref on returned surface */
6342 if(*ppRenderTarget != NULL)
6343 IWineD3DSurface_AddRef(*ppRenderTarget);
6347 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6349 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6350 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6351 IWineD3DSwapChainImpl *Swapchain;
6354 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6356 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6357 if(hr != WINED3D_OK) {
6358 ERR("Can't get the swapchain\n");
6362 /* Make sure to release the swapchain */
6363 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6365 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6366 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6367 return WINED3DERR_INVALIDCALL;
6369 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6370 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6371 return WINED3DERR_INVALIDCALL;
6374 if(Swapchain->frontBuffer != Front) {
6375 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6377 if(Swapchain->frontBuffer)
6378 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6379 Swapchain->frontBuffer = Front;
6381 if(Swapchain->frontBuffer) {
6382 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6386 if(Back && !Swapchain->backBuffer) {
6387 /* We need memory for the back buffer array - only one back buffer this way */
6388 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6389 if(!Swapchain->backBuffer) {
6390 ERR("Out of memory\n");
6391 return E_OUTOFMEMORY;
6395 if(Swapchain->backBuffer[0] != Back) {
6396 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6398 /* What to do about the context here in the case of multithreading? Not sure.
6399 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6402 if(!Swapchain->backBuffer[0]) {
6403 /* GL was told to draw to the front buffer at creation,
6406 glDrawBuffer(GL_BACK);
6407 checkGLcall("glDrawBuffer(GL_BACK)");
6408 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6409 Swapchain->presentParms.BackBufferCount = 1;
6411 /* That makes problems - disable for now */
6412 /* glDrawBuffer(GL_FRONT); */
6413 checkGLcall("glDrawBuffer(GL_FRONT)");
6414 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6415 Swapchain->presentParms.BackBufferCount = 0;
6419 if(Swapchain->backBuffer[0])
6420 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6421 Swapchain->backBuffer[0] = Back;
6423 if(Swapchain->backBuffer[0]) {
6424 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6426 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6427 Swapchain->backBuffer = NULL;
6435 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 *ppZStencilSurface = This->stencilBufferTarget;
6438 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6440 if(*ppZStencilSurface != NULL) {
6441 /* Note inc ref on returned surface */
6442 IWineD3DSurface_AddRef(*ppZStencilSurface);
6445 return WINED3DERR_NOTFOUND;
6449 /* TODO: Handle stencil attachments */
6450 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6453 TRACE("Set depth stencil to %p\n", depth_stencil);
6455 if (depth_stencil) {
6456 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6458 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6459 checkGLcall("glFramebufferTexture2DEXT()");
6463 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6466 TRACE("Set render target %u to %p\n", idx, render_target);
6468 if (render_target) {
6469 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6470 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6472 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6473 checkGLcall("glFramebufferTexture2DEXT()");
6475 This->draw_buffers[idx] = GL_NONE;
6479 static void check_fbo_status(IWineD3DDevice *iface) {
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6483 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6484 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6485 TRACE("FBO complete\n");
6487 IWineD3DSurfaceImpl *attachment;
6489 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6491 /* Dump the FBO attachments */
6492 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6493 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6495 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6496 attachment->pow2Width, attachment->pow2Height);
6499 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6501 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6502 attachment->pow2Width, attachment->pow2Height);
6507 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6509 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6510 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6512 if (!ds_impl) return FALSE;
6514 if (ds_impl->current_renderbuffer) {
6515 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6516 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6519 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6520 rt_impl->pow2Height != ds_impl->pow2Height);
6523 void apply_fbo_state(IWineD3DDevice *iface) {
6524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6527 if (This->render_offscreen) {
6528 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6530 /* Apply render targets */
6531 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6532 IWineD3DSurface *render_target = This->render_targets[i];
6533 if (This->fbo_color_attachments[i] != render_target) {
6534 set_render_target_fbo(iface, i, render_target);
6535 This->fbo_color_attachments[i] = render_target;
6539 /* Apply depth targets */
6540 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6541 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6542 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6544 if (This->stencilBufferTarget) {
6545 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6547 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6548 This->fbo_depth_attachment = This->stencilBufferTarget;
6551 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6552 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6553 checkGLcall("glDrawBuffers()");
6555 glDrawBuffer(This->draw_buffers[0]);
6556 checkGLcall("glDrawBuffer()");
6559 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6562 check_fbo_status(iface);
6565 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6566 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6568 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6569 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6572 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6573 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6574 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6575 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6578 case WINED3DTEXF_LINEAR:
6579 gl_filter = GL_LINEAR;
6583 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6584 case WINED3DTEXF_NONE:
6585 case WINED3DTEXF_POINT:
6586 gl_filter = GL_NEAREST;
6590 /* Attach src surface to src fbo */
6591 src_swapchain = get_swapchain(src_surface);
6592 if (src_swapchain) {
6595 TRACE("Source surface %p is onscreen\n", src_surface);
6596 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6597 /* Make sure the drawable is up to date. In the offscreen case
6598 * attach_surface_fbo() implicitly takes care of this. */
6599 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6602 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6603 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6604 glReadBuffer(buffer);
6605 checkGLcall("glReadBuffer()");
6607 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6608 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6610 TRACE("Source surface %p is offscreen\n", src_surface);
6612 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6613 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6614 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6615 checkGLcall("glReadBuffer()");
6616 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6617 checkGLcall("glFramebufferRenderbufferEXT");
6621 /* Attach dst surface to dst fbo */
6622 dst_swapchain = get_swapchain(dst_surface);
6623 if (dst_swapchain) {
6626 TRACE("Destination surface %p is onscreen\n", dst_surface);
6627 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6628 /* Make sure the drawable is up to date. In the offscreen case
6629 * attach_surface_fbo() implicitly takes care of this. */
6630 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6633 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6634 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6635 glDrawBuffer(buffer);
6636 checkGLcall("glDrawBuffer()");
6638 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6639 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6641 TRACE("Destination surface %p is offscreen\n", dst_surface);
6643 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6644 if(!src_swapchain) {
6645 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6649 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6650 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6651 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6652 checkGLcall("glDrawBuffer()");
6653 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6654 checkGLcall("glFramebufferRenderbufferEXT");
6656 glDisable(GL_SCISSOR_TEST);
6657 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6660 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6661 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6662 checkGLcall("glBlitFramebuffer()");
6664 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6665 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6666 checkGLcall("glBlitFramebuffer()");
6669 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6671 if (This->render_offscreen) {
6672 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6674 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6675 checkGLcall("glBindFramebuffer()");
6678 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6679 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6680 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6681 glDrawBuffer(GL_BACK);
6682 checkGLcall("glDrawBuffer()");
6687 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6689 WINED3DVIEWPORT viewport;
6691 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6693 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6694 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6695 This, RenderTargetIndex, GL_LIMITS(buffers));
6696 return WINED3DERR_INVALIDCALL;
6699 /* MSDN says that null disables the render target
6700 but a device must always be associated with a render target
6701 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6703 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6704 FIXME("Trying to set render target 0 to NULL\n");
6705 return WINED3DERR_INVALIDCALL;
6707 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6708 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);
6709 return WINED3DERR_INVALIDCALL;
6712 /* If we are trying to set what we already have, don't bother */
6713 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6714 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6717 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6718 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6719 This->render_targets[RenderTargetIndex] = pRenderTarget;
6721 /* Render target 0 is special */
6722 if(RenderTargetIndex == 0) {
6723 /* Finally, reset the viewport as the MSDN states. */
6724 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6725 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6728 viewport.MaxZ = 1.0f;
6729 viewport.MinZ = 0.0f;
6730 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6731 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6732 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6734 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6739 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6741 HRESULT hr = WINED3D_OK;
6742 IWineD3DSurface *tmp;
6744 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6746 if (pNewZStencil == This->stencilBufferTarget) {
6747 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6749 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6750 * depending on the renter target implementation being used.
6751 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6752 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6753 * stencil buffer and incur an extra memory overhead
6754 ******************************************************/
6756 tmp = This->stencilBufferTarget;
6757 This->stencilBufferTarget = pNewZStencil;
6758 This->depth_copy_state = WINED3D_DCS_NO_COPY;
6759 /* should we be calling the parent or the wined3d surface? */
6760 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6761 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6764 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6765 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6775 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6776 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6778 /* TODO: the use of Impl is deprecated. */
6779 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6780 WINED3DLOCKED_RECT lockedRect;
6782 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6784 /* some basic validation checks */
6785 if(This->cursorTexture) {
6786 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6788 glDeleteTextures(1, &This->cursorTexture);
6790 This->cursorTexture = 0;
6793 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6794 This->haveHardwareCursor = TRUE;
6796 This->haveHardwareCursor = FALSE;
6799 WINED3DLOCKED_RECT rect;
6801 /* MSDN: Cursor must be A8R8G8B8 */
6802 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6803 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6804 return WINED3DERR_INVALIDCALL;
6807 /* MSDN: Cursor must be smaller than the display mode */
6808 if(pSur->currentDesc.Width > This->ddraw_width ||
6809 pSur->currentDesc.Height > This->ddraw_height) {
6810 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);
6811 return WINED3DERR_INVALIDCALL;
6814 if (!This->haveHardwareCursor) {
6815 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6817 /* Do not store the surface's pointer because the application may
6818 * release it after setting the cursor image. Windows doesn't
6819 * addref the set surface, so we can't do this either without
6820 * creating circular refcount dependencies. Copy out the gl texture
6823 This->cursorWidth = pSur->currentDesc.Width;
6824 This->cursorHeight = pSur->currentDesc.Height;
6825 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6827 const GlPixelFormatDesc *glDesc;
6828 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6829 char *mem, *bits = (char *)rect.pBits;
6830 GLint intfmt = glDesc->glInternal;
6831 GLint format = glDesc->glFormat;
6832 GLint type = glDesc->glType;
6833 INT height = This->cursorHeight;
6834 INT width = This->cursorWidth;
6835 INT bpp = tableEntry->bpp;
6838 /* Reformat the texture memory (pitch and width can be
6840 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6841 for(i = 0; i < height; i++)
6842 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6843 IWineD3DSurface_UnlockRect(pCursorBitmap);
6846 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6847 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6848 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6851 /* Make sure that a proper texture unit is selected */
6852 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6853 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6854 checkGLcall("glActiveTextureARB");
6856 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
6857 /* Create a new cursor texture */
6858 glGenTextures(1, &This->cursorTexture);
6859 checkGLcall("glGenTextures");
6860 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6861 checkGLcall("glBindTexture");
6862 /* Copy the bitmap memory into the cursor texture */
6863 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6864 HeapFree(GetProcessHeap(), 0, mem);
6865 checkGLcall("glTexImage2D");
6867 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6868 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6869 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6876 FIXME("A cursor texture was not returned.\n");
6877 This->cursorTexture = 0;
6882 /* Draw a hardware cursor */
6883 ICONINFO cursorInfo;
6885 /* Create and clear maskBits because it is not needed for
6886 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6888 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6889 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6890 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6891 WINED3DLOCK_NO_DIRTY_UPDATE |
6892 WINED3DLOCK_READONLY
6894 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6895 pSur->currentDesc.Height);
6897 cursorInfo.fIcon = FALSE;
6898 cursorInfo.xHotspot = XHotSpot;
6899 cursorInfo.yHotspot = YHotSpot;
6900 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6901 pSur->currentDesc.Height, 1,
6903 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6904 pSur->currentDesc.Height, 1,
6905 32, lockedRect.pBits);
6906 IWineD3DSurface_UnlockRect(pCursorBitmap);
6907 /* Create our cursor and clean up. */
6908 cursor = CreateIconIndirect(&cursorInfo);
6910 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6911 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6912 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6913 This->hardwareCursor = cursor;
6914 HeapFree(GetProcessHeap(), 0, maskBits);
6918 This->xHotSpot = XHotSpot;
6919 This->yHotSpot = YHotSpot;
6923 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6925 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6927 This->xScreenSpace = XScreenSpace;
6928 This->yScreenSpace = YScreenSpace;
6934 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6936 BOOL oldVisible = This->bCursorVisible;
6939 TRACE("(%p) : visible(%d)\n", This, bShow);
6942 * When ShowCursor is first called it should make the cursor appear at the OS's last
6943 * known cursor position. Because of this, some applications just repetitively call
6944 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6947 This->xScreenSpace = pt.x;
6948 This->yScreenSpace = pt.y;
6950 if (This->haveHardwareCursor) {
6951 This->bCursorVisible = bShow;
6953 SetCursor(This->hardwareCursor);
6959 if (This->cursorTexture)
6960 This->bCursorVisible = bShow;
6966 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6968 IWineD3DResourceImpl *resource;
6969 TRACE("(%p) : state (%u)\n", This, This->state);
6971 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6972 switch (This->state) {
6975 case WINED3DERR_DEVICELOST:
6977 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6978 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6979 return WINED3DERR_DEVICENOTRESET;
6981 return WINED3DERR_DEVICELOST;
6983 case WINED3DERR_DRIVERINTERNALERROR:
6984 return WINED3DERR_DRIVERINTERNALERROR;
6988 return WINED3DERR_DRIVERINTERNALERROR;
6992 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6993 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6994 /** FIXME: Resource tracking needs to be done,
6995 * The closes we can do to this is set the priorities of all managed textures low
6996 * and then reset them.
6997 ***********************************************************/
6998 FIXME("(%p) : stub\n", This);
7002 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7003 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7005 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7006 if(surface->Flags & SFLAG_DIBSECTION) {
7007 /* Release the DC */
7008 SelectObject(surface->hDC, surface->dib.holdbitmap);
7009 DeleteDC(surface->hDC);
7010 /* Release the DIB section */
7011 DeleteObject(surface->dib.DIBsection);
7012 surface->dib.bitmap_data = NULL;
7013 surface->resource.allocatedMemory = NULL;
7014 surface->Flags &= ~SFLAG_DIBSECTION;
7016 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7017 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7018 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE)) {
7019 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7020 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7022 surface->pow2Width = surface->pow2Height = 1;
7023 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7024 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7026 surface->glRect.left = 0;
7027 surface->glRect.top = 0;
7028 surface->glRect.right = surface->pow2Width;
7029 surface->glRect.bottom = surface->pow2Height;
7031 if(surface->glDescription.textureName) {
7032 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7034 glDeleteTextures(1, &surface->glDescription.textureName);
7036 surface->glDescription.textureName = 0;
7037 surface->Flags &= ~SFLAG_CLIENT;
7039 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7040 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7041 surface->Flags |= SFLAG_NONPOW2;
7043 surface->Flags &= ~SFLAG_NONPOW2;
7045 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7046 surface->resource.allocatedMemory = NULL;
7047 surface->resource.heapMemory = NULL;
7048 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7049 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7050 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7051 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7053 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7057 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7058 TRACE("Unloading resource %p\n", resource);
7059 IWineD3DResource_UnLoad(resource);
7060 IWineD3DResource_Release(resource);
7064 static void reset_fbo_state(IWineD3DDevice *iface) {
7065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7069 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7070 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7073 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7076 if (This->src_fbo) {
7077 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7080 if (This->dst_fbo) {
7081 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7084 checkGLcall("Tear down FBOs\n");
7087 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7088 This->fbo_color_attachments[i] = NULL;
7090 This->fbo_depth_attachment = NULL;
7093 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7095 WINED3DDISPLAYMODE m;
7098 /* All Windowed modes are supported, as is leaving the current mode */
7099 if(pp->Windowed) return TRUE;
7100 if(!pp->BackBufferWidth) return TRUE;
7101 if(!pp->BackBufferHeight) return TRUE;
7103 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7104 for(i = 0; i < count; i++) {
7105 memset(&m, 0, sizeof(m));
7106 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7108 ERR("EnumAdapterModes failed\n");
7110 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7111 /* Mode found, it is supported */
7115 /* Mode not found -> not supported */
7119 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7121 IWineD3DSwapChainImpl *swapchain;
7123 BOOL DisplayModeChanged = FALSE;
7124 WINED3DDISPLAYMODE mode;
7125 IWineD3DBaseShaderImpl *shader;
7126 IWineD3DSurfaceImpl *target;
7128 TRACE("(%p)\n", This);
7130 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7132 ERR("Failed to get the first implicit swapchain\n");
7136 if(!is_display_mode_supported(This, pPresentationParameters)) {
7137 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7138 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7139 pPresentationParameters->BackBufferHeight);
7140 return WINED3DERR_INVALIDCALL;
7143 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7144 * on an existing gl context, so there's no real need for recreation.
7146 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7148 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7150 TRACE("New params:\n");
7151 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7152 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7153 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7154 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7155 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7156 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7157 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7158 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7159 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7160 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7161 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7162 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7163 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7165 /* No special treatment of these parameters. Just store them */
7166 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7167 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7168 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7169 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7171 /* What to do about these? */
7172 if(pPresentationParameters->BackBufferCount != 0 &&
7173 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7174 ERR("Cannot change the back buffer count yet\n");
7176 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7177 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7178 ERR("Cannot change the back buffer format yet\n");
7180 if(pPresentationParameters->hDeviceWindow != NULL &&
7181 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7182 ERR("Cannot change the device window yet\n");
7184 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7185 ERR("What do do about a changed auto depth stencil parameter?\n");
7188 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7189 reset_fbo_state((IWineD3DDevice *) This);
7192 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7193 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7194 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7198 if(This->depth_blt_texture) {
7199 glDeleteTextures(1, &This->depth_blt_texture);
7200 This->depth_blt_texture = 0;
7202 This->shader_backend->shader_destroy_depth_blt(iface);
7203 This->shader_backend->shader_free_private(iface);
7205 for (i = 0; i < GL_LIMITS(textures); i++) {
7206 /* Textures are recreated below */
7207 glDeleteTextures(1, &This->dummyTextureName[i]);
7208 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7209 This->dummyTextureName[i] = 0;
7213 while(This->numContexts) {
7214 DestroyContext(This, This->contexts[0]);
7216 This->activeContext = NULL;
7217 HeapFree(GetProcessHeap(), 0, swapchain->context);
7218 swapchain->context = NULL;
7219 swapchain->num_contexts = 0;
7221 if(pPresentationParameters->Windowed) {
7222 mode.Width = swapchain->orig_width;
7223 mode.Height = swapchain->orig_height;
7224 mode.RefreshRate = 0;
7225 mode.Format = swapchain->presentParms.BackBufferFormat;
7227 mode.Width = pPresentationParameters->BackBufferWidth;
7228 mode.Height = pPresentationParameters->BackBufferHeight;
7229 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7230 mode.Format = swapchain->presentParms.BackBufferFormat;
7233 /* Should Width == 800 && Height == 0 set 800x600? */
7234 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7235 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7236 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7243 vp.Width = pPresentationParameters->BackBufferWidth;
7244 vp.Height = pPresentationParameters->BackBufferHeight;
7248 if(!pPresentationParameters->Windowed) {
7249 DisplayModeChanged = TRUE;
7251 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7252 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7254 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7255 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7256 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7258 if(This->auto_depth_stencil_buffer) {
7259 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7263 /* Now set the new viewport */
7264 IWineD3DDevice_SetViewport(iface, &vp);
7267 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7268 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7269 DisplayModeChanged) {
7271 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7272 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7273 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7274 } else if(!pPresentationParameters->Windowed) {
7275 DWORD style = This->style, exStyle = This->exStyle;
7276 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7277 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7278 * Reset to clear up their mess. Guild Wars also loses the device during that.
7282 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7283 This->style = style;
7284 This->exStyle = exStyle;
7287 /* Recreate the primary swapchain's context */
7288 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7289 if(swapchain->backBuffer) {
7290 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7292 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7294 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7295 &swapchain->presentParms);
7296 swapchain->num_contexts = 1;
7297 This->activeContext = swapchain->context[0];
7298 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7300 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7302 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7304 create_dummy_textures(This);
7307 hr = This->shader_backend->shader_alloc_private(iface);
7309 ERR("Failed to recreate shader private data\n");
7313 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7319 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7321 /** FIXME: always true at the moment **/
7322 if(!bEnableDialogs) {
7323 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7329 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7331 TRACE("(%p) : pParameters %p\n", This, pParameters);
7333 *pParameters = This->createParms;
7337 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7338 IWineD3DSwapChain *swapchain;
7340 TRACE("Relaying to swapchain\n");
7342 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7343 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7344 IWineD3DSwapChain_Release(swapchain);
7349 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7350 IWineD3DSwapChain *swapchain;
7352 TRACE("Relaying to swapchain\n");
7354 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7355 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7356 IWineD3DSwapChain_Release(swapchain);
7362 /** ********************************************************
7363 * Notification functions
7364 ** ********************************************************/
7365 /** This function must be called in the release of a resource when ref == 0,
7366 * the contents of resource must still be correct,
7367 * any handles to other resource held by the caller must be closed
7368 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7369 *****************************************************/
7370 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7371 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7373 TRACE("(%p) : Adding Resource %p\n", This, resource);
7374 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7377 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7380 TRACE("(%p) : Removing resource %p\n", This, resource);
7382 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7386 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7390 TRACE("(%p) : resource %p\n", This, resource);
7391 switch(IWineD3DResource_GetType(resource)){
7392 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7393 case WINED3DRTYPE_SURFACE: {
7396 /* Cleanup any FBO attachments if d3d is enabled */
7397 if(This->d3d_initialized) {
7398 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7399 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7401 TRACE("Last active render target destroyed\n");
7402 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7403 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7404 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7405 * and the lastActiveRenderTarget member shouldn't matter
7408 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7409 TRACE("Activating primary back buffer\n");
7410 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7411 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7412 /* Single buffering environment */
7413 TRACE("Activating primary front buffer\n");
7414 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7416 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7417 /* Implicit render target destroyed, that means the device is being destroyed
7418 * whatever we set here, it shouldn't matter
7420 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7423 /* May happen during ddraw uninitialization */
7424 TRACE("Render target set, but swapchain does not exist!\n");
7425 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7430 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7431 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7432 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7433 set_render_target_fbo(iface, i, NULL);
7434 This->fbo_color_attachments[i] = NULL;
7437 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7438 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7439 set_depth_stencil_fbo(iface, NULL);
7440 This->fbo_depth_attachment = NULL;
7447 case WINED3DRTYPE_TEXTURE:
7448 case WINED3DRTYPE_CUBETEXTURE:
7449 case WINED3DRTYPE_VOLUMETEXTURE:
7450 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7451 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7452 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7453 This->stateBlock->textures[counter] = NULL;
7455 if (This->updateStateBlock != This->stateBlock ){
7456 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7457 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7458 This->updateStateBlock->textures[counter] = NULL;
7463 case WINED3DRTYPE_VOLUME:
7464 /* TODO: nothing really? */
7466 case WINED3DRTYPE_VERTEXBUFFER:
7467 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7470 TRACE("Cleaning up stream pointers\n");
7472 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7473 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7474 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7476 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7477 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7478 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7479 This->updateStateBlock->streamSource[streamNumber] = 0;
7480 /* Set changed flag? */
7483 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) */
7484 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7485 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7486 This->stateBlock->streamSource[streamNumber] = 0;
7489 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7490 else { /* This shouldn't happen */
7491 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7498 case WINED3DRTYPE_INDEXBUFFER:
7499 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7500 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7501 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7502 This->updateStateBlock->pIndexData = NULL;
7505 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7506 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7507 This->stateBlock->pIndexData = NULL;
7513 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7518 /* Remove the resource from the resourceStore */
7519 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7521 TRACE("Resource released\n");
7525 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7527 IWineD3DResourceImpl *resource, *cursor;
7529 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7531 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7532 TRACE("enumerating resource %p\n", resource);
7533 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7534 ret = pCallback((IWineD3DResource *) resource, pData);
7535 if(ret == S_FALSE) {
7536 TRACE("Canceling enumeration\n");
7543 /**********************************************************
7544 * IWineD3DDevice VTbl follows
7545 **********************************************************/
7547 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7549 /*** IUnknown methods ***/
7550 IWineD3DDeviceImpl_QueryInterface,
7551 IWineD3DDeviceImpl_AddRef,
7552 IWineD3DDeviceImpl_Release,
7553 /*** IWineD3DDevice methods ***/
7554 IWineD3DDeviceImpl_GetParent,
7555 /*** Creation methods**/
7556 IWineD3DDeviceImpl_CreateVertexBuffer,
7557 IWineD3DDeviceImpl_CreateIndexBuffer,
7558 IWineD3DDeviceImpl_CreateStateBlock,
7559 IWineD3DDeviceImpl_CreateSurface,
7560 IWineD3DDeviceImpl_CreateTexture,
7561 IWineD3DDeviceImpl_CreateVolumeTexture,
7562 IWineD3DDeviceImpl_CreateVolume,
7563 IWineD3DDeviceImpl_CreateCubeTexture,
7564 IWineD3DDeviceImpl_CreateQuery,
7565 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7566 IWineD3DDeviceImpl_CreateVertexDeclaration,
7567 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7568 IWineD3DDeviceImpl_CreateVertexShader,
7569 IWineD3DDeviceImpl_CreatePixelShader,
7570 IWineD3DDeviceImpl_CreatePalette,
7571 /*** Odd functions **/
7572 IWineD3DDeviceImpl_Init3D,
7573 IWineD3DDeviceImpl_Uninit3D,
7574 IWineD3DDeviceImpl_SetFullscreen,
7575 IWineD3DDeviceImpl_SetMultithreaded,
7576 IWineD3DDeviceImpl_EvictManagedResources,
7577 IWineD3DDeviceImpl_GetAvailableTextureMem,
7578 IWineD3DDeviceImpl_GetBackBuffer,
7579 IWineD3DDeviceImpl_GetCreationParameters,
7580 IWineD3DDeviceImpl_GetDeviceCaps,
7581 IWineD3DDeviceImpl_GetDirect3D,
7582 IWineD3DDeviceImpl_GetDisplayMode,
7583 IWineD3DDeviceImpl_SetDisplayMode,
7584 IWineD3DDeviceImpl_GetHWND,
7585 IWineD3DDeviceImpl_SetHWND,
7586 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7587 IWineD3DDeviceImpl_GetRasterStatus,
7588 IWineD3DDeviceImpl_GetSwapChain,
7589 IWineD3DDeviceImpl_Reset,
7590 IWineD3DDeviceImpl_SetDialogBoxMode,
7591 IWineD3DDeviceImpl_SetCursorProperties,
7592 IWineD3DDeviceImpl_SetCursorPosition,
7593 IWineD3DDeviceImpl_ShowCursor,
7594 IWineD3DDeviceImpl_TestCooperativeLevel,
7595 /*** Getters and setters **/
7596 IWineD3DDeviceImpl_SetClipPlane,
7597 IWineD3DDeviceImpl_GetClipPlane,
7598 IWineD3DDeviceImpl_SetClipStatus,
7599 IWineD3DDeviceImpl_GetClipStatus,
7600 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7601 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7602 IWineD3DDeviceImpl_SetDepthStencilSurface,
7603 IWineD3DDeviceImpl_GetDepthStencilSurface,
7604 IWineD3DDeviceImpl_SetFVF,
7605 IWineD3DDeviceImpl_GetFVF,
7606 IWineD3DDeviceImpl_SetGammaRamp,
7607 IWineD3DDeviceImpl_GetGammaRamp,
7608 IWineD3DDeviceImpl_SetIndices,
7609 IWineD3DDeviceImpl_GetIndices,
7610 IWineD3DDeviceImpl_SetBaseVertexIndex,
7611 IWineD3DDeviceImpl_GetBaseVertexIndex,
7612 IWineD3DDeviceImpl_SetLight,
7613 IWineD3DDeviceImpl_GetLight,
7614 IWineD3DDeviceImpl_SetLightEnable,
7615 IWineD3DDeviceImpl_GetLightEnable,
7616 IWineD3DDeviceImpl_SetMaterial,
7617 IWineD3DDeviceImpl_GetMaterial,
7618 IWineD3DDeviceImpl_SetNPatchMode,
7619 IWineD3DDeviceImpl_GetNPatchMode,
7620 IWineD3DDeviceImpl_SetPaletteEntries,
7621 IWineD3DDeviceImpl_GetPaletteEntries,
7622 IWineD3DDeviceImpl_SetPixelShader,
7623 IWineD3DDeviceImpl_GetPixelShader,
7624 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7625 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7626 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7627 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7628 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7629 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7630 IWineD3DDeviceImpl_SetRenderState,
7631 IWineD3DDeviceImpl_GetRenderState,
7632 IWineD3DDeviceImpl_SetRenderTarget,
7633 IWineD3DDeviceImpl_GetRenderTarget,
7634 IWineD3DDeviceImpl_SetFrontBackBuffers,
7635 IWineD3DDeviceImpl_SetSamplerState,
7636 IWineD3DDeviceImpl_GetSamplerState,
7637 IWineD3DDeviceImpl_SetScissorRect,
7638 IWineD3DDeviceImpl_GetScissorRect,
7639 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7640 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7641 IWineD3DDeviceImpl_SetStreamSource,
7642 IWineD3DDeviceImpl_GetStreamSource,
7643 IWineD3DDeviceImpl_SetStreamSourceFreq,
7644 IWineD3DDeviceImpl_GetStreamSourceFreq,
7645 IWineD3DDeviceImpl_SetTexture,
7646 IWineD3DDeviceImpl_GetTexture,
7647 IWineD3DDeviceImpl_SetTextureStageState,
7648 IWineD3DDeviceImpl_GetTextureStageState,
7649 IWineD3DDeviceImpl_SetTransform,
7650 IWineD3DDeviceImpl_GetTransform,
7651 IWineD3DDeviceImpl_SetVertexDeclaration,
7652 IWineD3DDeviceImpl_GetVertexDeclaration,
7653 IWineD3DDeviceImpl_SetVertexShader,
7654 IWineD3DDeviceImpl_GetVertexShader,
7655 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7656 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7657 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7658 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7659 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7660 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7661 IWineD3DDeviceImpl_SetViewport,
7662 IWineD3DDeviceImpl_GetViewport,
7663 IWineD3DDeviceImpl_MultiplyTransform,
7664 IWineD3DDeviceImpl_ValidateDevice,
7665 IWineD3DDeviceImpl_ProcessVertices,
7666 /*** State block ***/
7667 IWineD3DDeviceImpl_BeginStateBlock,
7668 IWineD3DDeviceImpl_EndStateBlock,
7669 /*** Scene management ***/
7670 IWineD3DDeviceImpl_BeginScene,
7671 IWineD3DDeviceImpl_EndScene,
7672 IWineD3DDeviceImpl_Present,
7673 IWineD3DDeviceImpl_Clear,
7675 IWineD3DDeviceImpl_DrawPrimitive,
7676 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7677 IWineD3DDeviceImpl_DrawPrimitiveUP,
7678 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7679 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7680 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7681 IWineD3DDeviceImpl_DrawRectPatch,
7682 IWineD3DDeviceImpl_DrawTriPatch,
7683 IWineD3DDeviceImpl_DeletePatch,
7684 IWineD3DDeviceImpl_ColorFill,
7685 IWineD3DDeviceImpl_UpdateTexture,
7686 IWineD3DDeviceImpl_UpdateSurface,
7687 IWineD3DDeviceImpl_GetFrontBufferData,
7688 /*** object tracking ***/
7689 IWineD3DDeviceImpl_ResourceReleased,
7690 IWineD3DDeviceImpl_EnumResources
7693 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7695 /*** IUnknown methods ***/
7696 IWineD3DDeviceImpl_QueryInterface,
7697 IWineD3DDeviceImpl_AddRef,
7698 IWineD3DDeviceImpl_Release,
7699 /*** IWineD3DDevice methods ***/
7700 IWineD3DDeviceImpl_GetParent,
7701 /*** Creation methods**/
7702 IWineD3DDeviceImpl_CreateVertexBuffer,
7703 IWineD3DDeviceImpl_CreateIndexBuffer,
7704 IWineD3DDeviceImpl_CreateStateBlock,
7705 IWineD3DDeviceImpl_CreateSurface,
7706 IWineD3DDeviceImpl_CreateTexture,
7707 IWineD3DDeviceImpl_CreateVolumeTexture,
7708 IWineD3DDeviceImpl_CreateVolume,
7709 IWineD3DDeviceImpl_CreateCubeTexture,
7710 IWineD3DDeviceImpl_CreateQuery,
7711 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7712 IWineD3DDeviceImpl_CreateVertexDeclaration,
7713 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7714 IWineD3DDeviceImpl_CreateVertexShader,
7715 IWineD3DDeviceImpl_CreatePixelShader,
7716 IWineD3DDeviceImpl_CreatePalette,
7717 /*** Odd functions **/
7718 IWineD3DDeviceImpl_Init3D,
7719 IWineD3DDeviceImpl_Uninit3D,
7720 IWineD3DDeviceImpl_SetFullscreen,
7721 IWineD3DDeviceImpl_SetMultithreaded,
7722 IWineD3DDeviceImpl_EvictManagedResources,
7723 IWineD3DDeviceImpl_GetAvailableTextureMem,
7724 IWineD3DDeviceImpl_GetBackBuffer,
7725 IWineD3DDeviceImpl_GetCreationParameters,
7726 IWineD3DDeviceImpl_GetDeviceCaps,
7727 IWineD3DDeviceImpl_GetDirect3D,
7728 IWineD3DDeviceImpl_GetDisplayMode,
7729 IWineD3DDeviceImpl_SetDisplayMode,
7730 IWineD3DDeviceImpl_GetHWND,
7731 IWineD3DDeviceImpl_SetHWND,
7732 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7733 IWineD3DDeviceImpl_GetRasterStatus,
7734 IWineD3DDeviceImpl_GetSwapChain,
7735 IWineD3DDeviceImpl_Reset,
7736 IWineD3DDeviceImpl_SetDialogBoxMode,
7737 IWineD3DDeviceImpl_SetCursorProperties,
7738 IWineD3DDeviceImpl_SetCursorPosition,
7739 IWineD3DDeviceImpl_ShowCursor,
7740 IWineD3DDeviceImpl_TestCooperativeLevel,
7741 /*** Getters and setters **/
7742 IWineD3DDeviceImpl_SetClipPlane,
7743 IWineD3DDeviceImpl_GetClipPlane,
7744 IWineD3DDeviceImpl_SetClipStatus,
7745 IWineD3DDeviceImpl_GetClipStatus,
7746 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7747 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7748 IWineD3DDeviceImpl_SetDepthStencilSurface,
7749 IWineD3DDeviceImpl_GetDepthStencilSurface,
7750 IWineD3DDeviceImpl_SetFVF,
7751 IWineD3DDeviceImpl_GetFVF,
7752 IWineD3DDeviceImpl_SetGammaRamp,
7753 IWineD3DDeviceImpl_GetGammaRamp,
7754 IWineD3DDeviceImpl_SetIndices,
7755 IWineD3DDeviceImpl_GetIndices,
7756 IWineD3DDeviceImpl_SetBaseVertexIndex,
7757 IWineD3DDeviceImpl_GetBaseVertexIndex,
7758 IWineD3DDeviceImpl_SetLight,
7759 IWineD3DDeviceImpl_GetLight,
7760 IWineD3DDeviceImpl_SetLightEnable,
7761 IWineD3DDeviceImpl_GetLightEnable,
7762 IWineD3DDeviceImpl_SetMaterial,
7763 IWineD3DDeviceImpl_GetMaterial,
7764 IWineD3DDeviceImpl_SetNPatchMode,
7765 IWineD3DDeviceImpl_GetNPatchMode,
7766 IWineD3DDeviceImpl_SetPaletteEntries,
7767 IWineD3DDeviceImpl_GetPaletteEntries,
7768 IWineD3DDeviceImpl_SetPixelShader,
7769 IWineD3DDeviceImpl_GetPixelShader,
7770 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7771 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7772 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7773 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7774 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7775 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7776 IWineD3DDeviceImpl_SetRenderState,
7777 IWineD3DDeviceImpl_GetRenderState,
7778 IWineD3DDeviceImpl_SetRenderTarget,
7779 IWineD3DDeviceImpl_GetRenderTarget,
7780 IWineD3DDeviceImpl_SetFrontBackBuffers,
7781 IWineD3DDeviceImpl_SetSamplerState,
7782 IWineD3DDeviceImpl_GetSamplerState,
7783 IWineD3DDeviceImpl_SetScissorRect,
7784 IWineD3DDeviceImpl_GetScissorRect,
7785 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7786 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7787 IWineD3DDeviceImpl_SetStreamSource,
7788 IWineD3DDeviceImpl_GetStreamSource,
7789 IWineD3DDeviceImpl_SetStreamSourceFreq,
7790 IWineD3DDeviceImpl_GetStreamSourceFreq,
7791 IWineD3DDeviceImpl_SetTexture,
7792 IWineD3DDeviceImpl_GetTexture,
7793 IWineD3DDeviceImpl_SetTextureStageState,
7794 IWineD3DDeviceImpl_GetTextureStageState,
7795 IWineD3DDeviceImpl_SetTransform,
7796 IWineD3DDeviceImpl_GetTransform,
7797 IWineD3DDeviceImpl_SetVertexDeclaration,
7798 IWineD3DDeviceImpl_GetVertexDeclaration,
7799 IWineD3DDeviceImpl_SetVertexShader,
7800 IWineD3DDeviceImpl_GetVertexShader,
7801 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7802 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7803 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7804 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7805 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7806 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7807 IWineD3DDeviceImpl_SetViewport,
7808 IWineD3DDeviceImpl_GetViewport,
7809 IWineD3DDeviceImpl_MultiplyTransform,
7810 IWineD3DDeviceImpl_ValidateDevice,
7811 IWineD3DDeviceImpl_ProcessVertices,
7812 /*** State block ***/
7813 IWineD3DDeviceImpl_BeginStateBlock,
7814 IWineD3DDeviceImpl_EndStateBlock,
7815 /*** Scene management ***/
7816 IWineD3DDeviceImpl_BeginScene,
7817 IWineD3DDeviceImpl_EndScene,
7818 IWineD3DDeviceImpl_Present,
7819 IWineD3DDeviceImpl_Clear,
7821 IWineD3DDeviceImpl_DrawPrimitive,
7822 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7823 IWineD3DDeviceImpl_DrawPrimitiveUP,
7824 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7825 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7826 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7827 IWineD3DDeviceImpl_DrawRectPatch,
7828 IWineD3DDeviceImpl_DrawTriPatch,
7829 IWineD3DDeviceImpl_DeletePatch,
7830 IWineD3DDeviceImpl_ColorFill,
7831 IWineD3DDeviceImpl_UpdateTexture,
7832 IWineD3DDeviceImpl_UpdateSurface,
7833 IWineD3DDeviceImpl_GetFrontBufferData,
7834 /*** object tracking ***/
7835 IWineD3DDeviceImpl_ResourceReleased,
7836 IWineD3DDeviceImpl_EnumResources
7839 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7840 WINED3DRS_ALPHABLENDENABLE ,
7841 WINED3DRS_ALPHAFUNC ,
7842 WINED3DRS_ALPHAREF ,
7843 WINED3DRS_ALPHATESTENABLE ,
7845 WINED3DRS_COLORWRITEENABLE ,
7846 WINED3DRS_DESTBLEND ,
7847 WINED3DRS_DITHERENABLE ,
7848 WINED3DRS_FILLMODE ,
7849 WINED3DRS_FOGDENSITY ,
7851 WINED3DRS_FOGSTART ,
7852 WINED3DRS_LASTPIXEL ,
7853 WINED3DRS_SHADEMODE ,
7854 WINED3DRS_SRCBLEND ,
7855 WINED3DRS_STENCILENABLE ,
7856 WINED3DRS_STENCILFAIL ,
7857 WINED3DRS_STENCILFUNC ,
7858 WINED3DRS_STENCILMASK ,
7859 WINED3DRS_STENCILPASS ,
7860 WINED3DRS_STENCILREF ,
7861 WINED3DRS_STENCILWRITEMASK ,
7862 WINED3DRS_STENCILZFAIL ,
7863 WINED3DRS_TEXTUREFACTOR ,
7874 WINED3DRS_ZWRITEENABLE
7877 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7878 WINED3DTSS_ADDRESSW ,
7879 WINED3DTSS_ALPHAARG0 ,
7880 WINED3DTSS_ALPHAARG1 ,
7881 WINED3DTSS_ALPHAARG2 ,
7882 WINED3DTSS_ALPHAOP ,
7883 WINED3DTSS_BUMPENVLOFFSET ,
7884 WINED3DTSS_BUMPENVLSCALE ,
7885 WINED3DTSS_BUMPENVMAT00 ,
7886 WINED3DTSS_BUMPENVMAT01 ,
7887 WINED3DTSS_BUMPENVMAT10 ,
7888 WINED3DTSS_BUMPENVMAT11 ,
7889 WINED3DTSS_COLORARG0 ,
7890 WINED3DTSS_COLORARG1 ,
7891 WINED3DTSS_COLORARG2 ,
7892 WINED3DTSS_COLOROP ,
7893 WINED3DTSS_RESULTARG ,
7894 WINED3DTSS_TEXCOORDINDEX ,
7895 WINED3DTSS_TEXTURETRANSFORMFLAGS
7898 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7899 WINED3DSAMP_ADDRESSU ,
7900 WINED3DSAMP_ADDRESSV ,
7901 WINED3DSAMP_ADDRESSW ,
7902 WINED3DSAMP_BORDERCOLOR ,
7903 WINED3DSAMP_MAGFILTER ,
7904 WINED3DSAMP_MINFILTER ,
7905 WINED3DSAMP_MIPFILTER ,
7906 WINED3DSAMP_MIPMAPLODBIAS ,
7907 WINED3DSAMP_MAXMIPLEVEL ,
7908 WINED3DSAMP_MAXANISOTROPY ,
7909 WINED3DSAMP_SRGBTEXTURE ,
7910 WINED3DSAMP_ELEMENTINDEX
7913 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7915 WINED3DRS_AMBIENTMATERIALSOURCE ,
7916 WINED3DRS_CLIPPING ,
7917 WINED3DRS_CLIPPLANEENABLE ,
7918 WINED3DRS_COLORVERTEX ,
7919 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7920 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7921 WINED3DRS_FOGDENSITY ,
7923 WINED3DRS_FOGSTART ,
7924 WINED3DRS_FOGTABLEMODE ,
7925 WINED3DRS_FOGVERTEXMODE ,
7926 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7927 WINED3DRS_LIGHTING ,
7928 WINED3DRS_LOCALVIEWER ,
7929 WINED3DRS_MULTISAMPLEANTIALIAS ,
7930 WINED3DRS_MULTISAMPLEMASK ,
7931 WINED3DRS_NORMALIZENORMALS ,
7932 WINED3DRS_PATCHEDGESTYLE ,
7933 WINED3DRS_POINTSCALE_A ,
7934 WINED3DRS_POINTSCALE_B ,
7935 WINED3DRS_POINTSCALE_C ,
7936 WINED3DRS_POINTSCALEENABLE ,
7937 WINED3DRS_POINTSIZE ,
7938 WINED3DRS_POINTSIZE_MAX ,
7939 WINED3DRS_POINTSIZE_MIN ,
7940 WINED3DRS_POINTSPRITEENABLE ,
7941 WINED3DRS_RANGEFOGENABLE ,
7942 WINED3DRS_SPECULARMATERIALSOURCE ,
7943 WINED3DRS_TWEENFACTOR ,
7944 WINED3DRS_VERTEXBLEND ,
7945 WINED3DRS_CULLMODE ,
7949 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7950 WINED3DTSS_TEXCOORDINDEX ,
7951 WINED3DTSS_TEXTURETRANSFORMFLAGS
7954 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7955 WINED3DSAMP_DMAPOFFSET
7958 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7959 DWORD rep = This->shader_backend->StateTable[state].representative;
7963 WineD3DContext *context;
7966 for(i = 0; i < This->numContexts; i++) {
7967 context = This->contexts[i];
7968 if(isStateDirty(context, rep)) continue;
7970 context->dirtyArray[context->numDirtyEntries++] = rep;
7973 context->isStateDirty[idx] |= (1 << shift);
7977 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7978 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7979 /* The drawable size of a pbuffer render target is the current pbuffer size
7981 *width = dev->pbufferWidth;
7982 *height = dev->pbufferHeight;
7985 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7986 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7988 *width = This->pow2Width;
7989 *height = This->pow2Height;
7992 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7993 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7994 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7995 * current context's drawable, which is the size of the back buffer of the swapchain
7996 * the active context belongs to. The back buffer of the swapchain is stored as the
7997 * surface the context belongs to.
7999 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8000 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;