2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 if (This->glsl_program_lookup) hash_table_destroy(This->glsl_program_lookup);
178 /* TODO: Clean up all the surfaces and textures! */
179 /* NOTE: You must release the parent if the object was created via a callback
180 ** ***************************/
182 if (!list_empty(&This->resources)) {
183 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
184 dumpResources(&This->resources);
187 if(This->contexts) ERR("Context array not freed!\n");
188 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
189 This->haveHardwareCursor = FALSE;
191 IWineD3D_Release(This->wineD3D);
192 This->wineD3D = NULL;
193 HeapFree(GetProcessHeap(), 0, This);
194 TRACE("Freed device %p\n", This);
200 /**********************************************************
201 * IWineD3DDevice implementation follows
202 **********************************************************/
203 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
205 *pParent = This->parent;
206 IUnknown_AddRef(This->parent);
210 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
211 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
214 IWineD3DVertexBufferImpl *object;
215 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
216 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
220 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
221 *ppVertexBuffer = NULL;
222 return WINED3DERR_INVALIDCALL;
223 } else if(Pool == WINED3DPOOL_SCRATCH) {
224 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
225 * anyway, SCRATCH vertex buffers aren't useable anywhere
227 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
228 *ppVertexBuffer = NULL;
229 return WINED3DERR_INVALIDCALL;
232 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
234 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
235 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
239 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
240 * drawStridedFast (half-life 2).
242 * Basically converting the vertices in the buffer is quite expensive, and observations
243 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
244 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
246 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
247 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
248 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
249 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
251 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
252 * more. In this call we can convert dx7 buffers too.
254 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
255 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
256 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
257 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
258 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
259 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
260 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
261 } else if(dxVersion <= 7 && conv) {
262 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
264 object->Flags |= VBFLAG_CREATEVBO;
269 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
270 GLenum error, glUsage;
271 TRACE("Creating VBO for Index Buffer %p\n", object);
273 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
274 * restored on the next draw
276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
278 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
279 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
284 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
285 error = glGetError();
286 if(error != GL_NO_ERROR || object->vbo == 0) {
287 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
291 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
298 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
299 * copy no readback will be needed
301 glUsage = GL_STATIC_DRAW_ARB;
302 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
303 error = glGetError();
304 if(error != GL_NO_ERROR) {
305 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
309 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
313 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
314 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
319 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
320 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
321 HANDLE *sharedHandle, IUnknown *parent) {
322 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
323 IWineD3DIndexBufferImpl *object;
324 TRACE("(%p) Creating index buffer\n", This);
326 /* Allocate the storage for the device */
327 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
329 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
330 CreateIndexBufferVBO(This, object);
333 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
334 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
335 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
340 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
343 IWineD3DStateBlockImpl *object;
347 D3DCREATEOBJECTINSTANCE(object, StateBlock)
348 object->blockType = Type;
350 for(i = 0; i < LIGHTMAP_SIZE; i++) {
351 list_init(&object->lightMap[i]);
354 /* Special case - Used during initialization to produce a placeholder stateblock
355 so other functions called can update a state block */
356 if (Type == WINED3DSBT_INIT) {
357 /* Don't bother increasing the reference count otherwise a device will never
358 be freed due to circular dependencies */
362 temp_result = allocate_shader_constants(object);
363 if (WINED3D_OK != temp_result)
366 /* Otherwise, might as well set the whole state block to the appropriate values */
367 if (This->stateBlock != NULL)
368 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
370 memset(object->streamFreq, 1, sizeof(object->streamFreq));
372 /* Reset the ref and type after kludging it */
373 object->wineD3DDevice = This;
375 object->blockType = Type;
377 TRACE("Updating changed flags appropriate for type %d\n", Type);
379 if (Type == WINED3DSBT_ALL) {
381 TRACE("ALL => Pretend everything has changed\n");
382 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
384 /* Lights are not part of the changed / set structure */
385 for(j = 0; j < LIGHTMAP_SIZE; j++) {
387 LIST_FOR_EACH(e, &object->lightMap[j]) {
388 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
389 light->changed = TRUE;
390 light->enabledChanged = TRUE;
393 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
394 object->contained_render_states[j - 1] = j;
396 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
397 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
398 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
399 object->contained_transform_states[j - 1] = j;
401 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
402 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
403 object->contained_vs_consts_f[j] = j;
405 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_vs_consts_i[j] = j;
409 object->num_contained_vs_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_vs_consts_b[j] = j;
413 object->num_contained_vs_consts_b = MAX_CONST_B;
414 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
415 object->contained_ps_consts_f[j] = j;
417 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
418 for(j = 0; j < MAX_CONST_I; j++) {
419 object->contained_ps_consts_i[j] = j;
421 object->num_contained_ps_consts_i = MAX_CONST_I;
422 for(j = 0; j < MAX_CONST_B; j++) {
423 object->contained_ps_consts_b[j] = j;
425 object->num_contained_ps_consts_b = MAX_CONST_B;
426 for(i = 0; i < MAX_TEXTURES; i++) {
427 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
428 object->contained_tss_states[object->num_contained_tss_states].stage = i;
429 object->contained_tss_states[object->num_contained_tss_states].state = j;
430 object->num_contained_tss_states++;
433 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
434 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
435 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
436 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
437 object->num_contained_sampler_states++;
441 for(i = 0; i < MAX_STREAMS; i++) {
442 if(object->streamSource[i]) {
443 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
446 if(object->pIndexData) {
447 IWineD3DIndexBuffer_AddRef(object->pIndexData);
449 if(object->vertexShader) {
450 IWineD3DVertexShader_AddRef(object->vertexShader);
452 if(object->pixelShader) {
453 IWineD3DPixelShader_AddRef(object->pixelShader);
456 } else if (Type == WINED3DSBT_PIXELSTATE) {
458 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
459 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
461 object->changed.pixelShader = TRUE;
463 /* Pixel Shader Constants */
464 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
465 object->contained_ps_consts_f[i] = i;
466 object->changed.pixelShaderConstantsF[i] = TRUE;
468 object->num_contained_ps_consts_f = GL_LIMITS(vshader_constantsF);
469 for (i = 0; i < MAX_CONST_B; ++i) {
470 object->contained_ps_consts_b[i] = i;
471 object->changed.pixelShaderConstantsB[i] = TRUE;
473 object->num_contained_ps_consts_b = MAX_CONST_B;
474 for (i = 0; i < MAX_CONST_I; ++i) {
475 object->contained_ps_consts_i[i] = i;
476 object->changed.pixelShaderConstantsI[i] = TRUE;
478 object->num_contained_ps_consts_i = MAX_CONST_I;
480 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
481 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
482 object->contained_render_states[i] = SavedPixelStates_R[i];
484 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
485 for (j = 0; j < MAX_TEXTURES; j++) {
486 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
487 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
488 object->contained_tss_states[object->num_contained_tss_states].stage = j;
489 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
490 object->num_contained_tss_states++;
493 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
494 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
495 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
496 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
497 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
498 object->num_contained_sampler_states++;
501 if(object->pixelShader) {
502 IWineD3DPixelShader_AddRef(object->pixelShader);
505 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
506 * on them. This makes releasing the buffer easier
508 for(i = 0; i < MAX_STREAMS; i++) {
509 object->streamSource[i] = NULL;
511 object->pIndexData = NULL;
512 object->vertexShader = NULL;
514 } else if (Type == WINED3DSBT_VERTEXSTATE) {
516 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
517 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
519 object->changed.vertexShader = TRUE;
521 /* Vertex Shader Constants */
522 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
523 object->changed.vertexShaderConstantsF[i] = TRUE;
524 object->contained_vs_consts_f[i] = i;
526 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
527 for (i = 0; i < MAX_CONST_B; ++i) {
528 object->changed.vertexShaderConstantsB[i] = TRUE;
529 object->contained_vs_consts_b[i] = i;
531 object->num_contained_vs_consts_b = MAX_CONST_B;
532 for (i = 0; i < MAX_CONST_I; ++i) {
533 object->changed.vertexShaderConstantsI[i] = TRUE;
534 object->contained_vs_consts_i[i] = i;
536 object->num_contained_vs_consts_i = MAX_CONST_I;
537 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
538 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
539 object->contained_render_states[i] = SavedVertexStates_R[i];
541 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
542 for (j = 0; j < MAX_TEXTURES; j++) {
543 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
544 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
545 object->contained_tss_states[object->num_contained_tss_states].stage = j;
546 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
547 object->num_contained_tss_states++;
550 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
551 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
552 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
555 object->num_contained_sampler_states++;
559 for(j = 0; j < LIGHTMAP_SIZE; j++) {
561 LIST_FOR_EACH(e, &object->lightMap[j]) {
562 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
563 light->changed = TRUE;
564 light->enabledChanged = TRUE;
568 for(i = 0; i < MAX_STREAMS; i++) {
569 if(object->streamSource[i]) {
570 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
573 if(object->vertexShader) {
574 IWineD3DVertexShader_AddRef(object->vertexShader);
576 object->pIndexData = NULL;
577 object->pixelShader = NULL;
579 FIXME("Unrecognized state block type %d\n", Type);
582 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
586 /* ************************************
588 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
591 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
593 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
595 ******************************** */
597 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
598 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
599 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
600 unsigned int Size = 1;
601 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
602 TRACE("(%p) Create surface\n",This);
604 /** FIXME: Check ranges on the inputs are valid
607 * [in] Quality level. The valid range is between zero and one less than the level
608 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
609 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
610 * values of paired render targets, depth stencil surfaces, and the MultiSample type
612 *******************************/
617 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
619 * If this flag is set, the contents of the depth stencil buffer will be
620 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
621 * with a different depth surface.
623 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
624 ***************************/
626 if(MultisampleQuality > 0) {
627 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
628 MultisampleQuality=0;
631 /** FIXME: Check that the format is supported
633 *******************************/
635 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
636 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
638 *********************************/
639 if (WINED3DFMT_UNKNOWN == Format) {
641 } else if (Format == WINED3DFMT_DXT1) {
642 /* DXT1 is half byte per pixel */
643 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
645 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
646 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5) {
647 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
649 /* The pitch is a multiple of 4 bytes */
650 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
654 /** Create and initialise the surface resource **/
655 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
656 /* "Standalone" surface */
657 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
659 object->currentDesc.Width = Width;
660 object->currentDesc.Height = Height;
661 object->currentDesc.MultiSampleType = MultiSample;
662 object->currentDesc.MultiSampleQuality = MultisampleQuality;
663 object->glDescription.level = Level;
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
687 case WINED3DPOOL_SCRATCH:
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
722 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
723 This->ddraw_primary = (IWineD3DSurface *) object;
725 /* Look at the implementation and set the correct Vtable */
728 /* Check if a 3D adapter is available when creating gl surfaces */
730 ERR("OpenGL surfaces are not available without opengl\n");
731 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
732 HeapFree(GetProcessHeap(), 0, object);
733 return WINED3DERR_NOTAVAILABLE;
738 object->lpVtbl = &IWineGDISurface_Vtbl;
742 /* To be sure to catch this */
743 ERR("Unknown requested surface implementation %d!\n", Impl);
744 IWineD3DSurface_Release((IWineD3DSurface *) object);
745 return WINED3DERR_INVALIDCALL;
748 list_init(&object->renderbuffers);
750 /* Call the private setup routine */
751 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
755 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
756 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
757 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
758 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
761 IWineD3DTextureImpl *object;
766 unsigned int pow2Width;
767 unsigned int pow2Height;
768 const GlPixelFormatDesc *glDesc;
769 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
771 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
772 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
773 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
775 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
776 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
777 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
778 return WINED3DERR_INVALIDCALL;
781 /* TODO: It should only be possible to create textures for formats
782 that are reported as supported */
783 if (WINED3DFMT_UNKNOWN >= Format) {
784 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
785 return WINED3DERR_INVALIDCALL;
788 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
789 D3DINITIALIZEBASETEXTURE(object->baseTexture);
790 object->width = Width;
791 object->height = Height;
793 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
794 object->baseTexture.minMipLookup = &minMipLookup;
795 object->baseTexture.magLookup = &magLookup;
797 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
798 object->baseTexture.magLookup = &magLookup_noFilter;
801 /** Non-power2 support **/
802 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
806 /* Find the nearest pow2 match */
807 pow2Width = pow2Height = 1;
808 while (pow2Width < Width) pow2Width <<= 1;
809 while (pow2Height < Height) pow2Height <<= 1;
811 if(pow2Width != Width || pow2Height != Height) {
813 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
814 HeapFree(GetProcessHeap(), 0, object);
816 return WINED3DERR_INVALIDCALL;
823 /** FIXME: add support for real non-power-two if it's provided by the video card **/
824 /* Precalculated scaling for 'faked' non power of two texture coords.
825 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
826 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
827 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
829 if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
830 (Width != pow2Width || Height != pow2Height) &&
831 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
833 object->baseTexture.pow2Matrix[0] = (float)Width;
834 object->baseTexture.pow2Matrix[5] = (float)Height;
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_RECTANGLE_ARB;
839 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
840 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
841 object->baseTexture.pow2Matrix[10] = 1.0;
842 object->baseTexture.pow2Matrix[15] = 1.0;
843 object->target = GL_TEXTURE_2D;
845 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
847 /* Calculate levels for mip mapping */
848 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
849 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
850 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
851 return WINED3DERR_INVALIDCALL;
854 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL;
857 object->baseTexture.levels = 1;
858 } else if (Levels == 0) {
859 TRACE("calculating levels %d\n", object->baseTexture.levels);
860 object->baseTexture.levels++;
863 while (tmpW > 1 || tmpH > 1) {
864 tmpW = max(1, tmpW >> 1);
865 tmpH = max(1, tmpH >> 1);
866 object->baseTexture.levels++;
868 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
871 /* Generate all the surfaces */
874 for (i = 0; i < object->baseTexture.levels; i++)
876 /* use the callback to create the texture surface */
877 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
878 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
879 FIXME("Failed to create surface %p\n", object);
881 object->surfaces[i] = NULL;
882 IWineD3DTexture_Release((IWineD3DTexture *)object);
888 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
889 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
890 /* calculate the next mipmap level */
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
894 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
896 TRACE("(%p) : Created texture %p\n", This, object);
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
901 UINT Width, UINT Height, UINT Depth,
902 UINT Levels, DWORD Usage,
903 WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DVolumeTexture **ppVolumeTexture,
905 HANDLE *pSharedHandle, IUnknown *parent,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 IWineD3DVolumeTextureImpl *object;
914 const GlPixelFormatDesc *glDesc;
916 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN >= Format) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
922 return WINED3DERR_INVALIDCALL;
924 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
926 return WINED3DERR_INVALIDCALL;
929 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
930 D3DINITIALIZEBASETEXTURE(object->baseTexture);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
935 object->width = Width;
936 object->height = Height;
937 object->depth = Depth;
939 /* Is NP2 support for volumes needed? */
940 object->baseTexture.pow2Matrix[ 0] = 1.0;
941 object->baseTexture.pow2Matrix[ 5] = 1.0;
942 object->baseTexture.pow2Matrix[10] = 1.0;
943 object->baseTexture.pow2Matrix[15] = 1.0;
945 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
946 object->baseTexture.minMipLookup = &minMipLookup;
947 object->baseTexture.magLookup = &magLookup;
949 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
950 object->baseTexture.magLookup = &magLookup_noFilter;
953 /* Calculate levels for mip mapping */
954 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL;
964 } else if (Levels == 0) {
965 object->baseTexture.levels++;
969 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
970 tmpW = max(1, tmpW >> 1);
971 tmpH = max(1, tmpH >> 1);
972 tmpD = max(1, tmpD >> 1);
973 object->baseTexture.levels++;
975 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
978 /* Generate all the surfaces */
983 for (i = 0; i < object->baseTexture.levels; i++)
986 /* Create the volume */
987 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
988 &object->volumes[i], pSharedHandle);
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
993 *ppVolumeTexture = NULL;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1000 /* calculate the next mipmap level */
1001 tmpW = max(1, tmpW >> 1);
1002 tmpH = max(1, tmpH >> 1);
1003 tmpD = max(1, tmpD >> 1);
1005 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1007 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1008 TRACE("(%p) : Created volume texture %p\n", This, object);
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1013 UINT Width, UINT Height, UINT Depth,
1015 WINED3DFORMAT Format, WINED3DPOOL Pool,
1016 IWineD3DVolume** ppVolume,
1017 HANDLE* pSharedHandle, IUnknown *parent) {
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1025 return WINED3DERR_INVALIDCALL;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1031 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1033 object->currentDesc.Width = Width;
1034 object->currentDesc.Height = Height;
1035 object->currentDesc.Depth = Depth;
1036 object->bytesPerPixel = formatDesc->bpp;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object->lockable = TRUE;
1040 object->locked = FALSE;
1041 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1042 object->dirty = TRUE;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1048 UINT Levels, DWORD Usage,
1049 WINED3DFORMAT Format, WINED3DPOOL Pool,
1050 IWineD3DCubeTexture **ppCubeTexture,
1051 HANDLE *pSharedHandle, IUnknown *parent,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int pow2EdgeLength = EdgeLength;
1060 const GlPixelFormatDesc *glDesc;
1061 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1063 if((Usage & (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) ==
1064 (WINED3DUSAGE_AUTOGENMIPMAP | WINED3DUSAGE_RENDERTARGET)) {
1065 WARN("Application requests both D3DUSAGE_AUTOGENMIPMAP and D3DUSAGE_RENDERTARGET, which are mutually exclusive\n");
1066 return WINED3DERR_INVALIDCALL;
1069 /* TODO: It should only be possible to create textures for formats
1070 that are reported as supported */
1071 if (WINED3DFMT_UNKNOWN >= Format) {
1072 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1073 return WINED3DERR_INVALIDCALL;
1076 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1077 WARN("(%p) : Tried to create not supported cube texture\n", This);
1078 return WINED3DERR_INVALIDCALL;
1081 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1082 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1084 TRACE("(%p) Create Cube Texture\n", This);
1086 /** Non-power2 support **/
1088 /* Find the nearest pow2 match */
1090 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1092 object->edgeLength = EdgeLength;
1093 /* TODO: support for native non-power 2 */
1094 /* Precalculated scaling for 'faked' non power of two texture coords */
1095 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1098 object->baseTexture.pow2Matrix[15] = 1.0;
1100 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1101 object->baseTexture.minMipLookup = &minMipLookup;
1102 object->baseTexture.magLookup = &magLookup;
1104 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1105 object->baseTexture.magLookup = &magLookup_noFilter;
1108 /* Calculate levels for mip mapping */
1109 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1110 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1111 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1112 HeapFree(GetProcessHeap(), 0, object);
1113 *ppCubeTexture = NULL;
1115 return WINED3DERR_INVALIDCALL;
1118 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1119 HeapFree(GetProcessHeap(), 0, object);
1120 *ppCubeTexture = NULL;
1122 return WINED3DERR_INVALIDCALL;
1125 } else if (Levels == 0) {
1126 object->baseTexture.levels++;
1129 tmpW = max(1, tmpW >> 1);
1130 object->baseTexture.levels++;
1132 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1135 /* Generate all the surfaces */
1137 for (i = 0; i < object->baseTexture.levels; i++) {
1139 /* Create the 6 faces */
1140 for (j = 0; j < 6; j++) {
1142 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1143 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1145 if(hr!= WINED3D_OK) {
1149 for (l = 0; l < j; l++) {
1150 IWineD3DSurface_Release(object->surfaces[l][i]);
1152 for (k = 0; k < i; k++) {
1153 for (l = 0; l < 6; l++) {
1154 IWineD3DSurface_Release(object->surfaces[l][k]);
1158 FIXME("(%p) Failed to create surface\n",object);
1159 HeapFree(GetProcessHeap(),0,object);
1160 *ppCubeTexture = NULL;
1163 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1164 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1166 tmpW = max(1, tmpW >> 1);
1168 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1170 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1171 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1175 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1176 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1177 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1178 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1179 const IWineD3DQueryVtbl *vtable;
1181 /* Just a check to see if we support this type of query */
1183 case WINED3DQUERYTYPE_OCCLUSION:
1184 TRACE("(%p) occlusion query\n", This);
1185 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1188 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1190 vtable = &IWineD3DOcclusionQuery_Vtbl;
1193 case WINED3DQUERYTYPE_EVENT:
1194 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1195 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1196 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1198 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1200 vtable = &IWineD3DEventQuery_Vtbl;
1204 case WINED3DQUERYTYPE_VCACHE:
1205 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1206 case WINED3DQUERYTYPE_VERTEXSTATS:
1207 case WINED3DQUERYTYPE_TIMESTAMP:
1208 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1209 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1210 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1211 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1212 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1213 case WINED3DQUERYTYPE_PIXELTIMINGS:
1214 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1215 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1217 /* Use the base Query vtable until we have a special one for each query */
1218 vtable = &IWineD3DQuery_Vtbl;
1219 FIXME("(%p) Unhandled query type %d\n", This, Type);
1221 if(NULL == ppQuery || hr != WINED3D_OK) {
1225 D3DCREATEOBJECTINSTANCE(object, Query)
1226 object->lpVtbl = vtable;
1227 object->type = Type;
1228 object->state = QUERY_CREATED;
1229 /* allocated the 'extended' data based on the type of query requested */
1231 case WINED3DQUERYTYPE_OCCLUSION:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1233 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1236 TRACE("(%p) Allocating data for an occlusion query\n", This);
1237 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1240 case WINED3DQUERYTYPE_EVENT:
1241 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1242 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1244 if(GL_SUPPORT(APPLE_FENCE)) {
1245 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesAPPLE");
1247 } else if(GL_SUPPORT(NV_FENCE)) {
1248 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1249 checkGLcall("glGenFencesNV");
1253 case WINED3DQUERYTYPE_VCACHE:
1254 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1255 case WINED3DQUERYTYPE_VERTEXSTATS:
1256 case WINED3DQUERYTYPE_TIMESTAMP:
1257 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1258 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1259 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1260 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1261 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1262 case WINED3DQUERYTYPE_PIXELTIMINGS:
1263 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1264 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1266 object->extendedData = 0;
1267 FIXME("(%p) Unhandled query type %d\n",This , Type);
1269 TRACE("(%p) : Created Query %p\n", This, object);
1273 /*****************************************************************************
1274 * IWineD3DDeviceImpl_SetupFullscreenWindow
1276 * Helper function that modifies a HWND's Style and ExStyle for proper
1280 * iface: Pointer to the IWineD3DDevice interface
1281 * window: Window to setup
1283 *****************************************************************************/
1284 static LONG fullscreen_style(LONG orig_style) {
1285 LONG style = orig_style;
1286 style &= ~WS_CAPTION;
1287 style &= ~WS_THICKFRAME;
1289 /* Make sure the window is managed, otherwise we won't get keyboard input */
1290 style |= WS_POPUP | WS_SYSMENU;
1295 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1296 LONG exStyle = orig_exStyle;
1298 /* Filter out window decorations */
1299 exStyle &= ~WS_EX_WINDOWEDGE;
1300 exStyle &= ~WS_EX_CLIENTEDGE;
1305 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1306 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1308 LONG style, exStyle;
1309 /* Don't do anything if an original style is stored.
1310 * That shouldn't happen
1312 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1313 if (This->style || This->exStyle) {
1314 ERR("(%p): Want to change the window parameters of HWND %p, but "
1315 "another style is stored for restoration afterwards\n", This, window);
1318 /* Get the parameters and save them */
1319 style = GetWindowLongW(window, GWL_STYLE);
1320 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1321 This->style = style;
1322 This->exStyle = exStyle;
1324 style = fullscreen_style(style);
1325 exStyle = fullscreen_exStyle(exStyle);
1327 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1328 This->style, This->exStyle, style, exStyle);
1330 SetWindowLongW(window, GWL_STYLE, style);
1331 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1333 /* Inform the window about the update. */
1334 SetWindowPos(window, HWND_TOP, 0, 0,
1335 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1336 ShowWindow(window, SW_NORMAL);
1339 /*****************************************************************************
1340 * IWineD3DDeviceImpl_RestoreWindow
1342 * Helper function that restores a windows' properties when taking it out
1343 * of fullscreen mode
1346 * iface: Pointer to the IWineD3DDevice interface
1347 * window: Window to setup
1349 *****************************************************************************/
1350 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1351 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1352 LONG style, exStyle;
1354 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1355 * switch, do nothing
1357 if (!This->style && !This->exStyle) return;
1359 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1360 This, window, This->style, This->exStyle);
1362 style = GetWindowLongW(window, GWL_STYLE);
1363 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1365 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1366 * Some applications change it before calling Reset() when switching between windowed and
1367 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1369 if(style == fullscreen_style(This->style) &&
1370 exStyle == fullscreen_style(This->exStyle)) {
1371 SetWindowLongW(window, GWL_STYLE, This->style);
1372 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1375 /* Delete the old values */
1379 /* Inform the window about the update */
1380 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1381 0, 0, 0, 0, /* Pos, Size, ignored */
1382 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1385 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1386 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1388 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1389 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1393 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 HRESULT hr = WINED3D_OK;
1395 IUnknown *bufferParent;
1396 BOOL displaymode_set = FALSE;
1397 WINED3DDISPLAYMODE Mode;
1398 const StaticPixelFormatDesc *formatDesc;
1400 TRACE("(%p) : Created Additional Swap Chain\n", This);
1402 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1403 * does a device hold a reference to a swap chain giving them a lifetime of the device
1404 * or does the swap chain notify the device of its destruction.
1405 *******************************/
1407 /* Check the params */
1408 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1409 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1410 return WINED3DERR_INVALIDCALL;
1411 } else if (pPresentationParameters->BackBufferCount > 1) {
1412 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1415 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1417 /*********************
1418 * Lookup the window Handle and the relating X window handle
1419 ********************/
1421 /* Setup hwnd we are using, plus which display this equates to */
1422 object->win_handle = pPresentationParameters->hDeviceWindow;
1423 if (!object->win_handle) {
1424 object->win_handle = This->createParms.hFocusWindow;
1426 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1428 hDc = GetDC(object->win_handle);
1429 TRACE("Using hDc %p\n", hDc);
1432 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1433 return WINED3DERR_NOTAVAILABLE;
1436 /* Get info on the current display setup */
1437 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1438 object->orig_width = Mode.Width;
1439 object->orig_height = Mode.Height;
1440 object->orig_fmt = Mode.Format;
1441 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1443 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1444 * then the corresponding dimension of the client area of the hDeviceWindow
1445 * (or the focus window, if hDeviceWindow is NULL) is taken.
1446 **********************/
1448 if (pPresentationParameters->Windowed &&
1449 ((pPresentationParameters->BackBufferWidth == 0) ||
1450 (pPresentationParameters->BackBufferHeight == 0) ||
1451 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1454 GetClientRect(object->win_handle, &Rect);
1456 if (pPresentationParameters->BackBufferWidth == 0) {
1457 pPresentationParameters->BackBufferWidth = Rect.right;
1458 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1460 if (pPresentationParameters->BackBufferHeight == 0) {
1461 pPresentationParameters->BackBufferHeight = Rect.bottom;
1462 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1464 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1465 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1466 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1470 /* Put the correct figures in the presentation parameters */
1471 TRACE("Copying across presentation parameters\n");
1472 object->presentParms = *pPresentationParameters;
1474 TRACE("calling rendertarget CB\n");
1475 hr = D3DCB_CreateRenderTarget(This->parent,
1477 object->presentParms.BackBufferWidth,
1478 object->presentParms.BackBufferHeight,
1479 object->presentParms.BackBufferFormat,
1480 object->presentParms.MultiSampleType,
1481 object->presentParms.MultiSampleQuality,
1482 TRUE /* Lockable */,
1483 &object->frontBuffer,
1484 NULL /* pShared (always null)*/);
1485 if (object->frontBuffer != NULL) {
1486 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1487 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1489 ERR("Failed to create the front buffer\n");
1493 /*********************
1494 * Windowed / Fullscreen
1495 *******************/
1498 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1499 * so we should really check to see if there is a fullscreen swapchain already
1500 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1501 **************************************/
1503 if (!pPresentationParameters->Windowed) {
1504 WINED3DDISPLAYMODE mode;
1507 /* Change the display settings */
1508 mode.Width = pPresentationParameters->BackBufferWidth;
1509 mode.Height = pPresentationParameters->BackBufferHeight;
1510 mode.Format = pPresentationParameters->BackBufferFormat;
1511 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1513 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1514 displaymode_set = TRUE;
1515 IWineD3DDevice_SetFullscreen(iface, TRUE);
1519 * Create an opengl context for the display visual
1520 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1521 * use different properties after that point in time. FIXME: How to handle when requested format
1522 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1523 * it chooses is identical to the one already being used!
1524 **********************************/
1525 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1527 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1528 if(!object->context)
1529 return E_OUTOFMEMORY;
1530 object->num_contexts = 1;
1532 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1533 if (!object->context[0]) {
1534 ERR("Failed to create a new context\n");
1535 hr = WINED3DERR_NOTAVAILABLE;
1538 TRACE("Context created (HWND=%p, glContext=%p)\n",
1539 object->win_handle, object->context[0]->glCtx);
1542 /*********************
1543 * Create the back, front and stencil buffers
1544 *******************/
1545 if(object->presentParms.BackBufferCount > 0) {
1548 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1549 if(!object->backBuffer) {
1550 ERR("Out of memory\n");
1555 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1556 TRACE("calling rendertarget CB\n");
1557 hr = D3DCB_CreateRenderTarget(This->parent,
1559 object->presentParms.BackBufferWidth,
1560 object->presentParms.BackBufferHeight,
1561 object->presentParms.BackBufferFormat,
1562 object->presentParms.MultiSampleType,
1563 object->presentParms.MultiSampleQuality,
1564 TRUE /* Lockable */,
1565 &object->backBuffer[i],
1566 NULL /* pShared (always null)*/);
1567 if(hr == WINED3D_OK && object->backBuffer[i]) {
1568 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1570 ERR("Cannot create new back buffer\n");
1574 glDrawBuffer(GL_BACK);
1575 checkGLcall("glDrawBuffer(GL_BACK)");
1579 object->backBuffer = NULL;
1581 /* Single buffering - draw to front buffer */
1583 glDrawBuffer(GL_FRONT);
1584 checkGLcall("glDrawBuffer(GL_FRONT)");
1588 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1589 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1590 TRACE("Creating depth stencil buffer\n");
1591 if (This->auto_depth_stencil_buffer == NULL ) {
1592 hr = D3DCB_CreateDepthStencil(This->parent,
1594 object->presentParms.BackBufferWidth,
1595 object->presentParms.BackBufferHeight,
1596 object->presentParms.AutoDepthStencilFormat,
1597 object->presentParms.MultiSampleType,
1598 object->presentParms.MultiSampleQuality,
1599 FALSE /* FIXME: Discard */,
1600 &This->auto_depth_stencil_buffer,
1601 NULL /* pShared (always null)*/ );
1602 if (This->auto_depth_stencil_buffer != NULL)
1603 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1606 /** TODO: A check on width, height and multisample types
1607 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1608 ****************************/
1609 object->wantsDepthStencilBuffer = TRUE;
1611 object->wantsDepthStencilBuffer = FALSE;
1614 TRACE("Created swapchain %p\n", object);
1615 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1619 if (displaymode_set) {
1623 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1626 /* Change the display settings */
1627 memset(&devmode, 0, sizeof(devmode));
1628 devmode.dmSize = sizeof(devmode);
1629 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1630 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1631 devmode.dmPelsWidth = object->orig_width;
1632 devmode.dmPelsHeight = object->orig_height;
1633 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1636 if (object->backBuffer) {
1638 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1639 if(object->backBuffer[i]) {
1640 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1641 IUnknown_Release(bufferParent); /* once for the get parent */
1642 if (IUnknown_Release(bufferParent) > 0) {
1643 FIXME("(%p) Something's still holding the back buffer\n",This);
1647 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1648 object->backBuffer = NULL;
1650 if(object->context[0])
1651 DestroyContext(This, object->context[0]);
1652 if(object->frontBuffer) {
1653 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1654 IUnknown_Release(bufferParent); /* once for the get parent */
1655 if (IUnknown_Release(bufferParent) > 0) {
1656 FIXME("(%p) Something's still holding the front buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object);
1663 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1664 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1666 TRACE("(%p)\n", This);
1668 return This->NumberOfSwapChains;
1671 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1672 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1673 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1675 if(iSwapChain < This->NumberOfSwapChains) {
1676 *pSwapChain = This->swapchains[iSwapChain];
1677 IWineD3DSwapChain_AddRef(*pSwapChain);
1678 TRACE("(%p) returning %p\n", This, *pSwapChain);
1681 TRACE("Swapchain out of range\n");
1683 return WINED3DERR_INVALIDCALL;
1688 * Vertex Declaration
1690 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1691 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1692 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1693 IWineD3DVertexDeclarationImpl *object = NULL;
1694 HRESULT hr = WINED3D_OK;
1696 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1697 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1699 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1701 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1703 *ppVertexDeclaration = NULL;
1704 HeapFree(GetProcessHeap(), 0, object);
1710 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1711 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1713 unsigned int idx, idx2;
1714 unsigned int offset;
1715 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1716 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1717 BOOL has_blend_idx = has_blend &&
1718 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1719 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1720 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1721 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1722 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1723 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1724 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1726 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1727 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1729 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1730 WINED3DVERTEXELEMENT *elements = NULL;
1733 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1734 if (has_blend_idx) num_blends--;
1736 /* Compute declaration size */
1737 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1738 has_psize + has_diffuse + has_specular + num_textures + 1;
1740 /* convert the declaration */
1741 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1745 elements[size-1] = end_element;
1748 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1749 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1750 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1753 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1754 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1756 elements[idx].UsageIndex = 0;
1759 if (has_blend && (num_blends > 0)) {
1760 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1761 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1763 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1764 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1765 elements[idx].UsageIndex = 0;
1768 if (has_blend_idx) {
1769 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1770 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1771 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1772 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1776 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1777 elements[idx].UsageIndex = 0;
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1782 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1783 elements[idx].UsageIndex = 0;
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1789 elements[idx].UsageIndex = 0;
1793 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1794 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1795 elements[idx].UsageIndex = 0;
1799 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1800 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1801 elements[idx].UsageIndex = 1;
1804 for (idx2 = 0; idx2 < num_textures; idx2++) {
1805 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1806 switch (numcoords) {
1807 case WINED3DFVF_TEXTUREFORMAT1:
1808 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 case WINED3DFVF_TEXTUREFORMAT2:
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1813 case WINED3DFVF_TEXTUREFORMAT3:
1814 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1816 case WINED3DFVF_TEXTUREFORMAT4:
1817 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1820 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1821 elements[idx].UsageIndex = idx2;
1825 /* Now compute offsets, and initialize the rest of the fields */
1826 for (idx = 0, offset = 0; idx < size-1; idx++) {
1827 elements[idx].Stream = 0;
1828 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1829 elements[idx].Offset = offset;
1830 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1833 *ppVertexElements = elements;
1837 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1838 WINED3DVERTEXELEMENT* elements = NULL;
1839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1843 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1844 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1846 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1847 HeapFree(GetProcessHeap(), 0, elements);
1848 if (hr != S_OK) return hr;
1853 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1855 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1856 HRESULT hr = WINED3D_OK;
1857 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1858 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1860 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1862 if (vertex_declaration) {
1863 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1866 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1868 if (WINED3D_OK != hr) {
1869 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1870 IWineD3DVertexShader_Release(*ppVertexShader);
1871 return WINED3DERR_INVALIDCALL;
1873 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1878 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1879 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1880 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1881 HRESULT hr = WINED3D_OK;
1883 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1884 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1885 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1886 if (WINED3D_OK == hr) {
1887 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1888 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1890 WARN("(%p) : Failed to create pixel shader\n", This);
1896 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1898 IWineD3DPaletteImpl *object;
1900 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1902 /* Create the new object */
1903 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1905 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1906 return E_OUTOFMEMORY;
1909 object->lpVtbl = &IWineD3DPalette_Vtbl;
1911 object->Flags = Flags;
1912 object->parent = Parent;
1913 object->wineD3DDevice = This;
1914 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1916 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1919 HeapFree( GetProcessHeap(), 0, object);
1920 return E_OUTOFMEMORY;
1923 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1925 IWineD3DPalette_Release((IWineD3DPalette *) object);
1929 *Palette = (IWineD3DPalette *) object;
1934 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1938 HDC dcb = NULL, dcs = NULL;
1939 WINEDDCOLORKEY colorkey;
1941 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1944 GetObjectA(hbm, sizeof(BITMAP), &bm);
1945 dcb = CreateCompatibleDC(NULL);
1947 SelectObject(dcb, hbm);
1951 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1952 * couldn't be loaded
1954 memset(&bm, 0, sizeof(bm));
1959 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1960 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1961 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1963 ERR("Wine logo requested, but failed to create surface\n");
1968 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1969 if(FAILED(hr)) goto out;
1970 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1971 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1973 colorkey.dwColorSpaceLowValue = 0;
1974 colorkey.dwColorSpaceHighValue = 0;
1975 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1977 /* Fill the surface with a white color to show that wined3d is there */
1978 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1991 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1993 /* Under DirectX you can have texture stage operations even if no texture is
1994 bound, whereas opengl will only do texture operations when a valid texture is
1995 bound. We emulate this by creating dummy textures and binding them to each
1996 texture stage, but disable all stages by default. Hence if a stage is enabled
1997 then the default texture will kick in until replaced by a SetTexture call */
2000 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2001 /* The dummy texture does not have client storage backing */
2002 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2003 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2005 for (i = 0; i < GL_LIMITS(textures); i++) {
2006 GLubyte white = 255;
2008 /* Make appropriate texture active */
2009 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2010 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2011 checkGLcall("glActiveTextureARB");
2013 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2016 /* Generate an opengl texture name */
2017 glGenTextures(1, &This->dummyTextureName[i]);
2018 checkGLcall("glGenTextures");
2019 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2021 /* Generate a dummy 2d texture (not using 1d because they cause many
2022 * DRI drivers fall back to sw) */
2023 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2024 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2025 checkGLcall("glBindTexture");
2027 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2028 checkGLcall("glTexImage2D");
2030 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2031 /* Reenable because if supported it is enabled by default */
2032 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2033 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2039 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2040 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2041 IWineD3DSwapChainImpl *swapchain = NULL;
2046 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2047 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2048 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2050 /* TODO: Test if OpenGL is compiled in and loaded */
2052 TRACE("(%p) : Creating stateblock\n", This);
2053 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2054 hr = IWineD3DDevice_CreateStateBlock(iface,
2056 (IWineD3DStateBlock **)&This->stateBlock,
2058 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2059 WARN("Failed to create stateblock\n");
2062 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2063 This->updateStateBlock = This->stateBlock;
2064 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2066 hr = allocate_shader_constants(This->updateStateBlock);
2067 if (WINED3D_OK != hr) {
2071 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2072 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2073 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2075 This->NumberOfPalettes = 1;
2076 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2077 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2078 ERR("Out of memory!\n");
2081 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2082 if(!This->palettes[0]) {
2083 ERR("Out of memory!\n");
2086 for (i = 0; i < 256; ++i) {
2087 This->palettes[0][i].peRed = 0xFF;
2088 This->palettes[0][i].peGreen = 0xFF;
2089 This->palettes[0][i].peBlue = 0xFF;
2090 This->palettes[0][i].peFlags = 0xFF;
2092 This->currentPalette = 0;
2094 /* Initialize the texture unit mapping to a 1:1 mapping */
2095 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2096 if (state < GL_LIMITS(fragment_samplers)) {
2097 This->texUnitMap[state] = state;
2098 This->rev_tex_unit_map[state] = state;
2100 This->texUnitMap[state] = -1;
2101 This->rev_tex_unit_map[state] = -1;
2105 /* Setup the implicit swapchain */
2106 TRACE("Creating implicit swapchain\n");
2107 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2108 if (FAILED(hr) || !swapchain) {
2109 WARN("Failed to create implicit swapchain\n");
2113 This->NumberOfSwapChains = 1;
2114 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2115 if(!This->swapchains) {
2116 ERR("Out of memory!\n");
2119 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2121 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2122 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2123 This->render_targets[0] = swapchain->backBuffer[0];
2124 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2127 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2128 This->render_targets[0] = swapchain->frontBuffer;
2129 This->lastActiveRenderTarget = swapchain->frontBuffer;
2131 IWineD3DSurface_AddRef(This->render_targets[0]);
2132 This->activeContext = swapchain->context[0];
2133 This->lastThread = GetCurrentThreadId();
2135 /* Depth Stencil support */
2136 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2137 if (NULL != This->stencilBufferTarget) {
2138 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2141 hr = This->shader_backend->shader_alloc_private(iface);
2143 TRACE("Shader private data couldn't be allocated\n");
2147 /* Set up some starting GL setup */
2149 /* Setup all the devices defaults */
2150 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2151 create_dummy_textures(This);
2156 IWineD3DImpl_CheckGraphicsMemory();
2159 { /* Set a default viewport */
2163 vp.Width = pPresentationParameters->BackBufferWidth;
2164 vp.Height = pPresentationParameters->BackBufferHeight;
2167 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2170 /* Initialize the current view state */
2171 This->view_ident = 1;
2172 This->contexts[0]->last_was_rhw = 0;
2173 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2174 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2176 switch(wined3d_settings.offscreen_rendering_mode) {
2179 This->offscreenBuffer = GL_BACK;
2182 case ORM_BACKBUFFER:
2184 if(This->activeContext->aux_buffers > 0) {
2185 TRACE("Using auxilliary buffer for offscreen rendering\n");
2186 This->offscreenBuffer = GL_AUX0;
2188 TRACE("Using back buffer for offscreen rendering\n");
2189 This->offscreenBuffer = GL_BACK;
2194 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2197 /* Clear the screen */
2198 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2199 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2202 This->d3d_initialized = TRUE;
2204 if(wined3d_settings.logo) {
2205 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2207 This->highest_dirty_ps_const = 0;
2208 This->highest_dirty_vs_const = 0;
2212 This->shader_backend->shader_free_private(iface);
2213 HeapFree(GetProcessHeap(), 0, This->render_targets);
2214 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2215 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2216 HeapFree(GetProcessHeap(), 0, This->swapchains);
2217 This->NumberOfSwapChains = 0;
2218 if(This->palettes) {
2219 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2220 HeapFree(GetProcessHeap(), 0, This->palettes);
2222 This->NumberOfPalettes = 0;
2224 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2226 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2227 if(This->stateBlock) {
2228 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2229 This->stateBlock = NULL;
2234 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2235 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2238 TRACE("(%p)\n", This);
2240 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2242 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2243 * it was created. Thus make sure a context is active for the glDelete* calls
2245 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2247 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2249 TRACE("Deleting high order patches\n");
2250 for(i = 0; i < PATCHMAP_SIZE; i++) {
2251 struct list *e1, *e2;
2252 struct WineD3DRectPatch *patch;
2253 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2254 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2255 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2259 /* Delete the palette conversion shader if it is around */
2260 if(This->paletteConversionShader) {
2262 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2264 This->paletteConversionShader = 0;
2267 /* Delete the pbuffer context if there is any */
2268 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2270 /* Delete the mouse cursor texture */
2271 if(This->cursorTexture) {
2273 glDeleteTextures(1, &This->cursorTexture);
2275 This->cursorTexture = 0;
2278 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2279 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2281 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2282 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2285 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2286 * private data, it might contain opengl pointers
2288 This->shader_backend->shader_destroy_depth_blt(iface);
2289 This->shader_backend->shader_free_private(iface);
2291 /* Release the update stateblock */
2292 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2293 if(This->updateStateBlock != This->stateBlock)
2294 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2296 This->updateStateBlock = NULL;
2298 { /* because were not doing proper internal refcounts releasing the primary state block
2299 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2300 to set this->stateBlock = NULL; first */
2301 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2302 This->stateBlock = NULL;
2304 /* Release the stateblock */
2305 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2306 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2310 /* Release the buffers (with sanity checks)*/
2311 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2312 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2313 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2314 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2316 This->stencilBufferTarget = NULL;
2318 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2319 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2320 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2322 TRACE("Setting rendertarget to NULL\n");
2323 This->render_targets[0] = NULL;
2325 if (This->auto_depth_stencil_buffer) {
2326 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2327 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2329 This->auto_depth_stencil_buffer = NULL;
2332 for(i=0; i < This->NumberOfSwapChains; i++) {
2333 TRACE("Releasing the implicit swapchain %d\n", i);
2334 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2335 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2339 HeapFree(GetProcessHeap(), 0, This->swapchains);
2340 This->swapchains = NULL;
2341 This->NumberOfSwapChains = 0;
2343 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2344 HeapFree(GetProcessHeap(), 0, This->palettes);
2345 This->palettes = NULL;
2346 This->NumberOfPalettes = 0;
2348 HeapFree(GetProcessHeap(), 0, This->render_targets);
2349 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2350 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2351 This->render_targets = NULL;
2352 This->fbo_color_attachments = NULL;
2353 This->draw_buffers = NULL;
2355 This->d3d_initialized = FALSE;
2359 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2361 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2363 /* Setup the window for fullscreen mode */
2364 if(fullscreen && !This->ddraw_fullscreen) {
2365 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2366 } else if(!fullscreen && This->ddraw_fullscreen) {
2367 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2370 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2371 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2372 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2375 This->ddraw_fullscreen = fullscreen;
2378 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2379 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2380 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2382 * There is no way to deactivate thread safety once it is enabled.
2384 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2387 /*For now just store the flag(needed in case of ddraw) */
2388 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2393 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2397 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2400 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2402 /* Resize the screen even without a window:
2403 * The app could have unset it with SetCooperativeLevel, but not called
2404 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2405 * but we don't have any hwnd
2408 memset(&devmode, 0, sizeof(devmode));
2409 devmode.dmSize = sizeof(devmode);
2410 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2411 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2412 devmode.dmPelsWidth = pMode->Width;
2413 devmode.dmPelsHeight = pMode->Height;
2415 devmode.dmDisplayFrequency = pMode->RefreshRate;
2416 if (pMode->RefreshRate != 0) {
2417 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2420 /* Only change the mode if necessary */
2421 if( (This->ddraw_width == pMode->Width) &&
2422 (This->ddraw_height == pMode->Height) &&
2423 (This->ddraw_format == pMode->Format) &&
2424 (pMode->RefreshRate == 0) ) {
2428 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2429 if (ret != DISP_CHANGE_SUCCESSFUL) {
2430 if(devmode.dmDisplayFrequency != 0) {
2431 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2432 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2433 devmode.dmDisplayFrequency = 0;
2434 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2436 if(ret != DISP_CHANGE_SUCCESSFUL) {
2437 return WINED3DERR_NOTAVAILABLE;
2441 /* Store the new values */
2442 This->ddraw_width = pMode->Width;
2443 This->ddraw_height = pMode->Height;
2444 This->ddraw_format = pMode->Format;
2446 /* Only do this with a window of course, and only if we're fullscreened */
2447 if(This->ddraw_window && This->ddraw_fullscreen)
2448 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2450 /* And finally clip mouse to our screen */
2451 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2452 ClipCursor(&clip_rc);
2457 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2459 *ppD3D= This->wineD3D;
2460 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2461 IWineD3D_AddRef(*ppD3D);
2465 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2466 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2469 (This->adapter->TextureRam/(1024*1024)),
2470 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2471 /* return simulated texture memory left */
2472 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2480 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2483 /* Update the current state block */
2484 This->updateStateBlock->changed.fvf = TRUE;
2486 if(This->updateStateBlock->fvf == fvf) {
2487 TRACE("Application is setting the old fvf over, nothing to do\n");
2491 This->updateStateBlock->fvf = fvf;
2492 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2493 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2498 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2499 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2500 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2501 *pfvf = This->stateBlock->fvf;
2506 * Get / Set Stream Source
2508 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2510 IWineD3DVertexBuffer *oldSrc;
2512 if (StreamNumber >= MAX_STREAMS) {
2513 WARN("Stream out of range %d\n", StreamNumber);
2514 return WINED3DERR_INVALIDCALL;
2515 } else if(OffsetInBytes & 0x3) {
2516 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2517 return WINED3DERR_INVALIDCALL;
2520 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2521 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2523 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2525 if(oldSrc == pStreamData &&
2526 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2527 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2528 TRACE("Application is setting the old values over, nothing to do\n");
2532 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2534 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2535 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2538 /* Handle recording of state blocks */
2539 if (This->isRecordingState) {
2540 TRACE("Recording... not performing anything\n");
2541 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2542 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2546 /* Need to do a getParent and pass the references up */
2547 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2548 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2549 so for now, just count internally */
2550 if (pStreamData != NULL) {
2551 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2552 InterlockedIncrement(&vbImpl->bindCount);
2553 IWineD3DVertexBuffer_AddRef(pStreamData);
2555 if (oldSrc != NULL) {
2556 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2557 IWineD3DVertexBuffer_Release(oldSrc);
2560 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2565 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2566 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2569 This->stateBlock->streamSource[StreamNumber],
2570 This->stateBlock->streamOffset[StreamNumber],
2571 This->stateBlock->streamStride[StreamNumber]);
2573 if (StreamNumber >= MAX_STREAMS) {
2574 WARN("Stream out of range %d\n", StreamNumber);
2575 return WINED3DERR_INVALIDCALL;
2577 *pStream = This->stateBlock->streamSource[StreamNumber];
2578 *pStride = This->stateBlock->streamStride[StreamNumber];
2580 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2583 if (*pStream != NULL) {
2584 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2589 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2591 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2592 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2594 /* Verify input at least in d3d9 this is invalid*/
2595 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2596 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2597 return WINED3DERR_INVALIDCALL;
2599 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2600 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2601 return WINED3DERR_INVALIDCALL;
2604 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2605 return WINED3DERR_INVALIDCALL;
2608 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2609 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2611 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2612 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2614 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2615 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2616 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2622 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2623 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2626 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2628 TRACE("(%p) : returning %d\n", This, *Divider);
2634 * Get / Set & Multiply Transform
2636 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2639 /* Most of this routine, comments included copied from ddraw tree initially: */
2640 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2642 /* Handle recording of state blocks */
2643 if (This->isRecordingState) {
2644 TRACE("Recording... not performing anything\n");
2645 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2646 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2651 * If the new matrix is the same as the current one,
2652 * we cut off any further processing. this seems to be a reasonable
2653 * optimization because as was noticed, some apps (warcraft3 for example)
2654 * tend towards setting the same matrix repeatedly for some reason.
2656 * From here on we assume that the new matrix is different, wherever it matters.
2658 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2659 TRACE("The app is setting the same matrix over again\n");
2662 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2666 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2667 where ViewMat = Camera space, WorldMat = world space.
2669 In OpenGL, camera and world space is combined into GL_MODELVIEW
2670 matrix. The Projection matrix stay projection matrix.
2673 /* Capture the times we can just ignore the change for now */
2674 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2675 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2676 /* Handled by the state manager */
2679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2685 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2686 *pMatrix = This->stateBlock->transforms[State];
2690 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2691 WINED3DMATRIX *mat = NULL;
2694 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2695 * below means it will be recorded in a state block change, but it
2696 * works regardless where it is recorded.
2697 * If this is found to be wrong, change to StateBlock.
2699 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2700 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2702 if (State < HIGHEST_TRANSFORMSTATE)
2704 mat = &This->updateStateBlock->transforms[State];
2706 FIXME("Unhandled transform state!!\n");
2709 multiply_matrix(&temp, mat, pMatrix);
2711 /* Apply change via set transform - will reapply to eg. lights this way */
2712 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2718 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2719 you can reference any indexes you want as long as that number max are enabled at any
2720 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2721 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2722 but when recording, just build a chain pretty much of commands to be replayed. */
2724 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2726 PLIGHTINFOEL *object = NULL;
2727 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2731 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2733 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2737 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2738 return WINED3DERR_INVALIDCALL;
2741 switch(pLight->Type) {
2742 case WINED3DLIGHT_POINT:
2743 case WINED3DLIGHT_SPOT:
2744 case WINED3DLIGHT_PARALLELPOINT:
2745 case WINED3DLIGHT_GLSPOT:
2746 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2749 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2750 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2751 return WINED3DERR_INVALIDCALL;
2755 case WINED3DLIGHT_DIRECTIONAL:
2756 /* Ignores attenuation */
2760 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2761 return WINED3DERR_INVALIDCALL;
2764 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2765 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2766 if(object->OriginalIndex == Index) break;
2771 TRACE("Adding new light\n");
2772 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2774 ERR("Out of memory error when allocating a light\n");
2775 return E_OUTOFMEMORY;
2777 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2778 object->glIndex = -1;
2779 object->OriginalIndex = Index;
2780 object->changed = TRUE;
2783 /* Initialize the object */
2784 TRACE("Light %d setting to type %d, Diffuse(%f,%f,%f,%f), Specular(%f,%f,%f,%f), Ambient(%f,%f,%f,%f)\n", Index, pLight->Type,
2785 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2786 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2787 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2788 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2789 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2790 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2792 /* Save away the information */
2793 object->OriginalParms = *pLight;
2795 switch (pLight->Type) {
2796 case WINED3DLIGHT_POINT:
2798 object->lightPosn[0] = pLight->Position.x;
2799 object->lightPosn[1] = pLight->Position.y;
2800 object->lightPosn[2] = pLight->Position.z;
2801 object->lightPosn[3] = 1.0f;
2802 object->cutoff = 180.0f;
2806 case WINED3DLIGHT_DIRECTIONAL:
2808 object->lightPosn[0] = -pLight->Direction.x;
2809 object->lightPosn[1] = -pLight->Direction.y;
2810 object->lightPosn[2] = -pLight->Direction.z;
2811 object->lightPosn[3] = 0.0;
2812 object->exponent = 0.0f;
2813 object->cutoff = 180.0f;
2816 case WINED3DLIGHT_SPOT:
2818 object->lightPosn[0] = pLight->Position.x;
2819 object->lightPosn[1] = pLight->Position.y;
2820 object->lightPosn[2] = pLight->Position.z;
2821 object->lightPosn[3] = 1.0;
2824 object->lightDirn[0] = pLight->Direction.x;
2825 object->lightDirn[1] = pLight->Direction.y;
2826 object->lightDirn[2] = pLight->Direction.z;
2827 object->lightDirn[3] = 1.0;
2830 * opengl-ish and d3d-ish spot lights use too different models for the
2831 * light "intensity" as a function of the angle towards the main light direction,
2832 * so we only can approximate very roughly.
2833 * however spot lights are rather rarely used in games (if ever used at all).
2834 * furthermore if still used, probably nobody pays attention to such details.
2836 if (pLight->Falloff == 0) {
2837 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2838 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2839 * will always be 1.0 for both of them, and we don't have to care for the
2840 * rest of the rather complex calculation
2842 object->exponent = 0;
2844 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2845 if (rho < 0.0001) rho = 0.0001f;
2846 object->exponent = -0.3/log(cos(rho/2));
2848 if (object->exponent > 128.0) {
2849 object->exponent = 128.0;
2851 object->cutoff = pLight->Phi*90/M_PI;
2857 FIXME("Unrecognized light type %d\n", pLight->Type);
2860 /* Update the live definitions if the light is currently assigned a glIndex */
2861 if (object->glIndex != -1 && !This->isRecordingState) {
2862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2867 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2868 PLIGHTINFOEL *lightInfo = NULL;
2869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2870 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2872 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2874 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2875 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2876 if(lightInfo->OriginalIndex == Index) break;
2880 if (lightInfo == NULL) {
2881 TRACE("Light information requested but light not defined\n");
2882 return WINED3DERR_INVALIDCALL;
2885 *pLight = lightInfo->OriginalParms;
2890 * Get / Set Light Enable
2891 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2893 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2894 PLIGHTINFOEL *lightInfo = NULL;
2895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2896 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2898 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2900 /* Tests show true = 128...not clear why */
2901 Enable = Enable? 128: 0;
2903 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2904 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2905 if(lightInfo->OriginalIndex == Index) break;
2908 TRACE("Found light: %p\n", lightInfo);
2910 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2911 if (lightInfo == NULL) {
2913 TRACE("Light enabled requested but light not defined, so defining one!\n");
2914 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2916 /* Search for it again! Should be fairly quick as near head of list */
2917 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2918 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2919 if(lightInfo->OriginalIndex == Index) break;
2922 if (lightInfo == NULL) {
2923 FIXME("Adding default lights has failed dismally\n");
2924 return WINED3DERR_INVALIDCALL;
2928 lightInfo->enabledChanged = TRUE;
2930 if(lightInfo->glIndex != -1) {
2931 if(!This->isRecordingState) {
2932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2935 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2936 lightInfo->glIndex = -1;
2938 TRACE("Light already disabled, nothing to do\n");
2940 lightInfo->enabled = FALSE;
2942 lightInfo->enabled = TRUE;
2943 if (lightInfo->glIndex != -1) {
2945 TRACE("Nothing to do as light was enabled\n");
2948 /* Find a free gl light */
2949 for(i = 0; i < This->maxConcurrentLights; i++) {
2950 if(This->stateBlock->activeLights[i] == NULL) {
2951 This->stateBlock->activeLights[i] = lightInfo;
2952 lightInfo->glIndex = i;
2956 if(lightInfo->glIndex == -1) {
2957 /* Our tests show that Windows returns D3D_OK in this situation, even with
2958 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2959 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2960 * as well for those lights.
2962 * TODO: Test how this affects rendering
2964 FIXME("Too many concurrently active lights\n");
2968 /* i == lightInfo->glIndex */
2969 if(!This->isRecordingState) {
2970 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2978 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2980 PLIGHTINFOEL *lightInfo = NULL;
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2983 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2984 TRACE("(%p) : for idx(%d)\n", This, Index);
2986 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2987 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2988 if(lightInfo->OriginalIndex == Index) break;
2992 if (lightInfo == NULL) {
2993 TRACE("Light enabled state requested but light not defined\n");
2994 return WINED3DERR_INVALIDCALL;
2996 /* true is 128 according to SetLightEnable */
2997 *pEnable = lightInfo->enabled ? 128 : 0;
3002 * Get / Set Clip Planes
3004 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3006 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3008 /* Validate Index */
3009 if (Index >= GL_LIMITS(clipplanes)) {
3010 TRACE("Application has requested clipplane this device doesn't support\n");
3011 return WINED3DERR_INVALIDCALL;
3014 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3016 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3017 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3018 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3019 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3020 TRACE("Application is setting old values over, nothing to do\n");
3024 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3025 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3026 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3027 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3029 /* Handle recording of state blocks */
3030 if (This->isRecordingState) {
3031 TRACE("Recording... not performing anything\n");
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3040 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3042 TRACE("(%p) : for idx %d\n", This, Index);
3044 /* Validate Index */
3045 if (Index >= GL_LIMITS(clipplanes)) {
3046 TRACE("Application has requested clipplane this device doesn't support\n");
3047 return WINED3DERR_INVALIDCALL;
3050 pPlane[0] = This->stateBlock->clipplane[Index][0];
3051 pPlane[1] = This->stateBlock->clipplane[Index][1];
3052 pPlane[2] = This->stateBlock->clipplane[Index][2];
3053 pPlane[3] = This->stateBlock->clipplane[Index][3];
3058 * Get / Set Clip Plane Status
3059 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3061 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3063 FIXME("(%p) : stub\n", This);
3064 if (NULL == pClipStatus) {
3065 return WINED3DERR_INVALIDCALL;
3067 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3068 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3072 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 FIXME("(%p) : stub\n", This);
3075 if (NULL == pClipStatus) {
3076 return WINED3DERR_INVALIDCALL;
3078 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3079 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3084 * Get / Set Material
3086 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3087 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3089 This->updateStateBlock->changed.material = TRUE;
3090 This->updateStateBlock->material = *pMaterial;
3092 /* Handle recording of state blocks */
3093 if (This->isRecordingState) {
3094 TRACE("Recording... not performing anything\n");
3098 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3102 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3104 *pMaterial = This->updateStateBlock->material;
3105 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3106 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3107 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3108 pMaterial->Ambient.b, pMaterial->Ambient.a);
3109 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3110 pMaterial->Specular.b, pMaterial->Specular.a);
3111 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3112 pMaterial->Emissive.b, pMaterial->Emissive.a);
3113 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3121 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3122 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 IWineD3DIndexBuffer *oldIdxs;
3125 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3126 oldIdxs = This->updateStateBlock->pIndexData;
3128 This->updateStateBlock->changed.indices = TRUE;
3129 This->updateStateBlock->pIndexData = pIndexData;
3131 /* Handle recording of state blocks */
3132 if (This->isRecordingState) {
3133 TRACE("Recording... not performing anything\n");
3134 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3135 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3139 if(oldIdxs != pIndexData) {
3140 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3141 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3142 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3147 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 *ppIndexData = This->stateBlock->pIndexData;
3152 /* up ref count on ppindexdata */
3154 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3155 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3157 TRACE("(%p) No index data set\n", This);
3159 TRACE("Returning %p\n", *ppIndexData);
3164 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3165 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3167 TRACE("(%p)->(%d)\n", This, BaseIndex);
3169 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3170 TRACE("Application is setting the old value over, nothing to do\n");
3174 This->updateStateBlock->baseVertexIndex = BaseIndex;
3176 if (This->isRecordingState) {
3177 TRACE("Recording... not performing anything\n");
3180 /* The base vertex index affects the stream sources */
3181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3185 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3187 TRACE("(%p) : base_index %p\n", This, base_index);
3189 *base_index = This->stateBlock->baseVertexIndex;
3191 TRACE("Returning %u\n", *base_index);
3197 * Get / Set Viewports
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3202 TRACE("(%p)\n", This);
3203 This->updateStateBlock->changed.viewport = TRUE;
3204 This->updateStateBlock->viewport = *pViewport;
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3212 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3213 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3220 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3222 TRACE("(%p)\n", This);
3223 *pViewport = This->stateBlock->viewport;
3228 * Get / Set Render States
3229 * TODO: Verify against dx9 definitions
3231 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3234 DWORD oldValue = This->stateBlock->renderState[State];
3236 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3238 This->updateStateBlock->changed.renderState[State] = TRUE;
3239 This->updateStateBlock->renderState[State] = Value;
3241 /* Handle recording of state blocks */
3242 if (This->isRecordingState) {
3243 TRACE("Recording... not performing anything\n");
3247 /* Compared here and not before the assignment to allow proper stateblock recording */
3248 if(Value == oldValue) {
3249 TRACE("Application is setting the old value over, nothing to do\n");
3251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3257 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3259 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3260 *pValue = This->stateBlock->renderState[State];
3265 * Get / Set Sampler States
3266 * TODO: Verify against dx9 definitions
3269 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3273 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3274 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3276 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3277 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3280 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3281 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3282 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3285 * SetSampler is designed to allow for more than the standard up to 8 textures
3286 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3287 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3289 * http://developer.nvidia.com/object/General_FAQ.html#t6
3291 * There are two new settings for GForce
3293 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3294 * and the texture one:
3295 * GL_MAX_TEXTURE_COORDS_ARB.
3296 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3299 oldValue = This->stateBlock->samplerState[Sampler][Type];
3300 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3301 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3303 /* Handle recording of state blocks */
3304 if (This->isRecordingState) {
3305 TRACE("Recording... not performing anything\n");
3309 if(oldValue == Value) {
3310 TRACE("Application is setting the old value over, nothing to do\n");
3314 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3319 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3323 This, Sampler, debug_d3dsamplerstate(Type), Type);
3325 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3326 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3329 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3330 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3331 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3333 *Value = This->stateBlock->samplerState[Sampler][Type];
3334 TRACE("(%p) : Returning %#x\n", This, *Value);
3339 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3342 This->updateStateBlock->changed.scissorRect = TRUE;
3343 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3344 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3347 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3349 if(This->isRecordingState) {
3350 TRACE("Recording... not performing anything\n");
3354 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3359 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3360 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3362 *pRect = This->updateStateBlock->scissorRect;
3363 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3367 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3368 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3369 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3371 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3373 This->updateStateBlock->vertexDecl = pDecl;
3374 This->updateStateBlock->changed.vertexDecl = TRUE;
3376 if (This->isRecordingState) {
3377 TRACE("Recording... not performing anything\n");
3379 } else if(pDecl == oldDecl) {
3380 /* Checked after the assignment to allow proper stateblock recording */
3381 TRACE("Application is setting the old declaration over, nothing to do\n");
3385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3389 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3394 *ppDecl = This->stateBlock->vertexDecl;
3395 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3399 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3400 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3401 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3403 This->updateStateBlock->vertexShader = pShader;
3404 This->updateStateBlock->changed.vertexShader = TRUE;
3406 if (This->isRecordingState) {
3407 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3408 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3409 TRACE("Recording... not performing anything\n");
3411 } else if(oldShader == pShader) {
3412 /* Checked here to allow proper stateblock recording */
3413 TRACE("App is setting the old shader over, nothing to do\n");
3417 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3418 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3419 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3426 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3429 if (NULL == ppShader) {
3430 return WINED3DERR_INVALIDCALL;
3432 *ppShader = This->stateBlock->vertexShader;
3433 if( NULL != *ppShader)
3434 IWineD3DVertexShader_AddRef(*ppShader);
3436 TRACE("(%p) : returning %p\n", This, *ppShader);
3440 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3441 IWineD3DDevice *iface,
3443 CONST BOOL *srcData,
3446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3447 int i, cnt = min(count, MAX_CONST_B - start);
3449 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3450 iface, srcData, start, count);
3452 if (srcData == NULL || cnt < 0)
3453 return WINED3DERR_INVALIDCALL;
3455 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3456 for (i = 0; i < cnt; i++)
3457 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3459 for (i = start; i < cnt + start; ++i) {
3460 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3463 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3468 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3469 IWineD3DDevice *iface,
3474 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3475 int cnt = min(count, MAX_CONST_B - start);
3477 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3478 iface, dstData, start, count);
3480 if (dstData == NULL || cnt < 0)
3481 return WINED3DERR_INVALIDCALL;
3483 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3487 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3488 IWineD3DDevice *iface,
3493 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 int i, cnt = min(count, MAX_CONST_I - start);
3496 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3497 iface, srcData, start, count);
3499 if (srcData == NULL || cnt < 0)
3500 return WINED3DERR_INVALIDCALL;
3502 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3503 for (i = 0; i < cnt; i++)
3504 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3505 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3507 for (i = start; i < cnt + start; ++i) {
3508 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3511 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3516 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3517 IWineD3DDevice *iface,
3522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3523 int cnt = min(count, MAX_CONST_I - start);
3525 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3526 iface, dstData, start, count);
3528 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3529 return WINED3DERR_INVALIDCALL;
3531 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3535 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3536 IWineD3DDevice *iface,
3538 CONST float *srcData,
3541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3545 iface, srcData, start, count);
3547 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3548 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3549 return WINED3DERR_INVALIDCALL;
3551 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3553 for (i = 0; i < count; i++)
3554 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3555 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3558 for (i = start; i < count + start; ++i) {
3559 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3560 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3561 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3562 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3563 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3565 ptr->idx[ptr->count++] = i;
3566 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3575 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3576 IWineD3DDevice *iface,
3578 CONST float *srcData,
3581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3585 iface, srcData, start, count);
3587 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3588 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3589 return WINED3DERR_INVALIDCALL;
3591 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3593 for (i = 0; i < count; i++)
3594 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3595 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3598 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3599 * context. On a context switch the old context will be fully dirtified
3601 memset(This->activeContext->vshader_const_dirty + start, 1,
3602 sizeof(*This->activeContext->vshader_const_dirty) * count);
3603 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count);
3605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3610 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3611 IWineD3DDevice *iface,
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3619 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3620 iface, dstData, start, count);
3622 if (dstData == NULL || cnt < 0)
3623 return WINED3DERR_INVALIDCALL;
3625 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3629 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3631 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3632 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3636 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3637 int i = This->rev_tex_unit_map[unit];
3638 int j = This->texUnitMap[stage];
3640 This->texUnitMap[stage] = unit;
3641 if (i != -1 && i != stage) {
3642 This->texUnitMap[i] = -1;
3645 This->rev_tex_unit_map[unit] = stage;
3646 if (j != -1 && j != unit) {
3647 This->rev_tex_unit_map[j] = -1;
3651 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3654 for (i = 0; i < MAX_TEXTURES; ++i) {
3655 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3656 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3657 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3658 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3659 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3660 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3661 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3662 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3664 if (color_op == WINED3DTOP_DISABLE) {
3665 /* Not used, and disable higher stages */
3666 while (i < MAX_TEXTURES) {
3667 This->fixed_function_usage_map[i] = FALSE;
3673 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3674 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3675 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3676 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3677 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3678 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3679 This->fixed_function_usage_map[i] = TRUE;
3681 This->fixed_function_usage_map[i] = FALSE;
3684 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3685 This->fixed_function_usage_map[i+1] = TRUE;
3690 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3693 device_update_fixed_function_usage_map(This);
3695 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3696 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3697 if (!This->fixed_function_usage_map[i]) continue;
3699 if (This->texUnitMap[i] != i) {
3700 device_map_stage(This, i, i);
3701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3702 markTextureStagesDirty(This, i);
3708 /* Now work out the mapping */
3710 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3711 if (!This->fixed_function_usage_map[i]) continue;
3713 if (This->texUnitMap[i] != tex) {
3714 device_map_stage(This, i, tex);
3715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3716 markTextureStagesDirty(This, i);
3723 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3724 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3727 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3728 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3729 device_map_stage(This, i, i);
3730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3731 if (i < MAX_TEXTURES) {
3732 markTextureStagesDirty(This, i);
3738 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3739 int current_mapping = This->rev_tex_unit_map[unit];
3741 if (current_mapping == -1) {
3742 /* Not currently used */
3746 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3747 /* Used by a fragment sampler */
3749 if (!pshader_sampler_tokens) {
3750 /* No pixel shader, check fixed function */
3751 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3754 /* Pixel shader, check the shader's sampler map */
3755 return !pshader_sampler_tokens[current_mapping];
3758 /* Used by a vertex sampler */
3759 return !vshader_sampler_tokens[current_mapping];
3762 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3763 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3764 DWORD *pshader_sampler_tokens = NULL;
3765 int start = GL_LIMITS(combined_samplers) - 1;
3769 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3771 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3772 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3773 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3776 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3777 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3778 if (vshader_sampler_tokens[i]) {
3779 if (This->texUnitMap[vsampler_idx] != -1) {
3780 /* Already mapped somewhere */
3784 while (start >= 0) {
3785 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3786 device_map_stage(This, vsampler_idx, start);
3787 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3799 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3800 BOOL vs = use_vs(This);
3801 BOOL ps = use_ps(This);
3804 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3805 * that would be really messy and require shader recompilation
3806 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3807 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3810 device_map_psamplers(This);
3812 device_map_fixed_function_samplers(This);
3816 device_map_vsamplers(This, ps);
3820 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3822 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3823 This->updateStateBlock->pixelShader = pShader;
3824 This->updateStateBlock->changed.pixelShader = TRUE;
3826 /* Handle recording of state blocks */
3827 if (This->isRecordingState) {
3828 TRACE("Recording... not performing anything\n");
3831 if (This->isRecordingState) {
3832 TRACE("Recording... not performing anything\n");
3833 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3834 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3838 if(pShader == oldShader) {
3839 TRACE("App is setting the old pixel shader over, nothing to do\n");
3843 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3844 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3846 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3852 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3853 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3855 if (NULL == ppShader) {
3856 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3857 return WINED3DERR_INVALIDCALL;
3860 *ppShader = This->stateBlock->pixelShader;
3861 if (NULL != *ppShader) {
3862 IWineD3DPixelShader_AddRef(*ppShader);
3864 TRACE("(%p) : returning %p\n", This, *ppShader);
3868 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3869 IWineD3DDevice *iface,
3871 CONST BOOL *srcData,
3874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3875 int i, cnt = min(count, MAX_CONST_B - start);
3877 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3878 iface, srcData, start, count);
3880 if (srcData == NULL || cnt < 0)
3881 return WINED3DERR_INVALIDCALL;
3883 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3884 for (i = 0; i < cnt; i++)
3885 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3887 for (i = start; i < cnt + start; ++i) {
3888 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3891 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3896 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3897 IWineD3DDevice *iface,
3902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3903 int cnt = min(count, MAX_CONST_B - start);
3905 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3906 iface, dstData, start, count);
3908 if (dstData == NULL || cnt < 0)
3909 return WINED3DERR_INVALIDCALL;
3911 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3915 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3916 IWineD3DDevice *iface,
3921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3922 int i, cnt = min(count, MAX_CONST_I - start);
3924 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3925 iface, srcData, start, count);
3927 if (srcData == NULL || cnt < 0)
3928 return WINED3DERR_INVALIDCALL;
3930 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3931 for (i = 0; i < cnt; i++)
3932 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3933 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3935 for (i = start; i < cnt + start; ++i) {
3936 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3944 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3945 IWineD3DDevice *iface,
3950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3951 int cnt = min(count, MAX_CONST_I - start);
3953 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3954 iface, dstData, start, count);
3956 if (dstData == NULL || cnt < 0)
3957 return WINED3DERR_INVALIDCALL;
3959 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3963 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3964 IWineD3DDevice *iface,
3966 CONST float *srcData,
3969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3973 iface, srcData, start, count);
3975 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3976 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3977 return WINED3DERR_INVALIDCALL;
3979 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3981 for (i = 0; i < count; i++)
3982 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3983 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3986 for (i = start; i < count + start; ++i) {
3987 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
3988 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
3989 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3990 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3991 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
3993 ptr->idx[ptr->count++] = i;
3994 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
3998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4003 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4004 IWineD3DDevice *iface,
4006 CONST float *srcData,
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4012 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4013 iface, srcData, start, count);
4015 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4016 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4017 return WINED3DERR_INVALIDCALL;
4019 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4021 for (i = 0; i < count; i++)
4022 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4023 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4026 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4027 * context. On a context switch the old context will be fully dirtified
4029 memset(This->activeContext->pshader_const_dirty + start, 1,
4030 sizeof(*This->activeContext->pshader_const_dirty) * count);
4031 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count);
4033 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4038 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4039 IWineD3DDevice *iface,
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4045 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4047 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4048 iface, dstData, start, count);
4050 if (dstData == NULL || cnt < 0)
4051 return WINED3DERR_INVALIDCALL;
4053 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4057 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4059 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4060 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4062 DWORD DestFVF = dest->fvf;
4064 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4068 if (lpStrideData->u.s.normal.lpData) {
4069 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4072 if (lpStrideData->u.s.position.lpData == NULL) {
4073 ERR("Source has no position mask\n");
4074 return WINED3DERR_INVALIDCALL;
4077 /* We might access VBOs from this code, so hold the lock */
4080 if (dest->resource.allocatedMemory == NULL) {
4081 /* This may happen if we do direct locking into a vbo. Unlikely,
4082 * but theoretically possible(ddraw processvertices test)
4084 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4085 if(!dest->resource.allocatedMemory) {
4087 ERR("Out of memory\n");
4088 return E_OUTOFMEMORY;
4092 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4093 checkGLcall("glBindBufferARB");
4094 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4096 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4098 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4099 checkGLcall("glUnmapBufferARB");
4103 /* Get a pointer into the destination vbo(create one if none exists) and
4104 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4106 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4107 dest->Flags |= VBFLAG_CREATEVBO;
4108 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4112 unsigned char extrabytes = 0;
4113 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4114 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4115 * this may write 4 extra bytes beyond the area that should be written
4117 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4118 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4119 if(!dest_conv_addr) {
4120 ERR("Out of memory\n");
4121 /* Continue without storing converted vertices */
4123 dest_conv = dest_conv_addr;
4127 * a) WINED3DRS_CLIPPING is enabled
4128 * b) WINED3DVOP_CLIP is passed
4130 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4131 static BOOL warned = FALSE;
4133 * The clipping code is not quite correct. Some things need
4134 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4135 * so disable clipping for now.
4136 * (The graphics in Half-Life are broken, and my processvertices
4137 * test crashes with IDirect3DDevice3)
4143 FIXME("Clipping is broken and disabled for now\n");
4145 } else doClip = FALSE;
4146 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4148 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4151 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4152 WINED3DTS_PROJECTION,
4154 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4155 WINED3DTS_WORLDMATRIX(0),
4158 TRACE("View mat:\n");
4159 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);
4160 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);
4161 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);
4162 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);
4164 TRACE("Proj mat:\n");
4165 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);
4166 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);
4167 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);
4168 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);
4170 TRACE("World mat:\n");
4171 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);
4172 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);
4173 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);
4174 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);
4176 /* Get the viewport */
4177 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4178 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4179 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4181 multiply_matrix(&mat,&view_mat,&world_mat);
4182 multiply_matrix(&mat,&proj_mat,&mat);
4184 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4186 for (i = 0; i < dwCount; i+= 1) {
4187 unsigned int tex_index;
4189 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4190 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4191 /* The position first */
4193 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4195 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4197 /* Multiplication with world, view and projection matrix */
4198 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);
4199 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);
4200 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);
4201 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);
4203 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4205 /* WARNING: The following things are taken from d3d7 and were not yet checked
4206 * against d3d8 or d3d9!
4209 /* Clipping conditions: From msdn
4211 * A vertex is clipped if it does not match the following requirements
4215 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4217 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4218 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4223 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4224 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4227 /* "Normal" viewport transformation (not clipped)
4228 * 1) The values are divided by rhw
4229 * 2) The y axis is negative, so multiply it with -1
4230 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4231 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4232 * 4) Multiply x with Width/2 and add Width/2
4233 * 5) The same for the height
4234 * 6) Add the viewpoint X and Y to the 2D coordinates and
4235 * The minimum Z value to z
4236 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4238 * Well, basically it's simply a linear transformation into viewport
4250 z *= vp.MaxZ - vp.MinZ;
4252 x += vp.Width / 2 + vp.X;
4253 y += vp.Height / 2 + vp.Y;
4258 /* That vertex got clipped
4259 * Contrary to OpenGL it is not dropped completely, it just
4260 * undergoes a different calculation.
4262 TRACE("Vertex got clipped\n");
4269 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4270 * outside of the main vertex buffer memory. That needs some more
4275 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4278 ( (float *) dest_ptr)[0] = x;
4279 ( (float *) dest_ptr)[1] = y;
4280 ( (float *) dest_ptr)[2] = z;
4281 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4283 dest_ptr += 3 * sizeof(float);
4285 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4286 dest_ptr += sizeof(float);
4291 ( (float *) dest_conv)[0] = x * w;
4292 ( (float *) dest_conv)[1] = y * w;
4293 ( (float *) dest_conv)[2] = z * w;
4294 ( (float *) dest_conv)[3] = w;
4296 dest_conv += 3 * sizeof(float);
4298 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4299 dest_conv += sizeof(float);
4303 if (DestFVF & WINED3DFVF_PSIZE) {
4304 dest_ptr += sizeof(DWORD);
4305 if(dest_conv) dest_conv += sizeof(DWORD);
4307 if (DestFVF & WINED3DFVF_NORMAL) {
4309 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4310 /* AFAIK this should go into the lighting information */
4311 FIXME("Didn't expect the destination to have a normal\n");
4312 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4314 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4318 if (DestFVF & WINED3DFVF_DIFFUSE) {
4320 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4322 static BOOL warned = FALSE;
4325 ERR("No diffuse color in source, but destination has one\n");
4329 *( (DWORD *) dest_ptr) = 0xffffffff;
4330 dest_ptr += sizeof(DWORD);
4333 *( (DWORD *) dest_conv) = 0xffffffff;
4334 dest_conv += sizeof(DWORD);
4338 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4340 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4341 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4342 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4343 dest_conv += sizeof(DWORD);
4348 if (DestFVF & WINED3DFVF_SPECULAR) {
4349 /* What's the color value in the feedback buffer? */
4351 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4353 static BOOL warned = FALSE;
4356 ERR("No specular color in source, but destination has one\n");
4360 *( (DWORD *) dest_ptr) = 0xFF000000;
4361 dest_ptr += sizeof(DWORD);
4364 *( (DWORD *) dest_conv) = 0xFF000000;
4365 dest_conv += sizeof(DWORD);
4369 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4371 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4372 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4373 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4374 dest_conv += sizeof(DWORD);
4379 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4381 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4382 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4384 ERR("No source texture, but destination requests one\n");
4385 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4386 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4389 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4391 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4398 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4399 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4400 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4401 dwCount * get_flexible_vertex_size(DestFVF),
4403 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4404 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4411 #undef copy_and_next
4413 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4415 WineDirect3DVertexStridedData strided;
4416 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4417 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4420 ERR("Output vertex declaration not implemented yet\n");
4423 /* Need any context to write to the vbo. */
4424 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4426 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4427 * control the streamIsUP flag, thus restore it afterwards.
4429 This->stateBlock->streamIsUP = FALSE;
4430 memset(&strided, 0, sizeof(strided));
4431 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4432 This->stateBlock->streamIsUP = streamWasUP;
4434 if(vbo || SrcStartIndex) {
4436 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4437 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4439 * Also get the start index in, but only loop over all elements if there's something to add at all.
4441 #define FIXSRC(type) \
4442 if(strided.u.s.type.VBO) { \
4443 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4444 strided.u.s.type.VBO = 0; \
4445 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4447 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4451 if(strided.u.s.type.lpData) { \
4452 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4455 FIXSRC(blendWeights);
4456 FIXSRC(blendMatrixIndices);
4461 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4462 FIXSRC(texCoords[i]);
4475 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4479 * Get / Set Texture Stage States
4480 * TODO: Verify against dx9 definitions
4482 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4484 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4486 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4488 if (Stage >= MAX_TEXTURES) {
4489 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4493 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4494 This->updateStateBlock->textureState[Stage][Type] = Value;
4496 if (This->isRecordingState) {
4497 TRACE("Recording... not performing anything\n");
4501 /* Checked after the assignments to allow proper stateblock recording */
4502 if(oldValue == Value) {
4503 TRACE("App is setting the old value over, nothing to do\n");
4507 if(Stage > This->stateBlock->lowest_disabled_stage &&
4508 This->shader_backend->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4509 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4510 * Changes in other states are important on disabled stages too
4515 if(Type == WINED3DTSS_COLOROP) {
4518 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4519 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4520 * they have to be disabled
4522 * The current stage is dirtified below.
4524 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4525 TRACE("Additionally dirtifying stage %d\n", i);
4526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4528 This->stateBlock->lowest_disabled_stage = Stage;
4529 TRACE("New lowest disabled: %d\n", Stage);
4530 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4531 /* Previously disabled stage enabled. Stages above it may need enabling
4532 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4533 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4535 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4538 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4539 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4542 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4543 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4545 This->stateBlock->lowest_disabled_stage = i;
4546 TRACE("New lowest disabled: %d\n", i);
4548 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4549 /* TODO: Built a stage -> texture unit mapping for register combiners */
4553 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4558 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4561 *pValue = This->updateStateBlock->textureState[Stage][Type];
4568 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4570 IWineD3DBaseTexture *oldTexture;
4572 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4574 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4575 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4578 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4579 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4580 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4583 oldTexture = This->updateStateBlock->textures[Stage];
4585 if(pTexture != NULL) {
4586 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4588 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4589 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4590 return WINED3DERR_INVALIDCALL;
4592 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4595 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4596 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4598 This->updateStateBlock->changed.textures[Stage] = TRUE;
4599 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4600 This->updateStateBlock->textures[Stage] = pTexture;
4602 /* Handle recording of state blocks */
4603 if (This->isRecordingState) {
4604 TRACE("Recording... not performing anything\n");
4608 if(oldTexture == pTexture) {
4609 TRACE("App is setting the same texture again, nothing to do\n");
4613 /** NOTE: MSDN says that setTexture increases the reference count,
4614 * and that the application must set the texture back to null (or have a leaky application),
4615 * This means we should pass the refcount up to the parent
4616 *******************************/
4617 if (NULL != This->updateStateBlock->textures[Stage]) {
4618 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4619 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4621 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4622 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4623 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4624 * so the COLOROP and ALPHAOP have to be dirtified.
4626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4629 if(bindCount == 1) {
4630 new->baseTexture.sampler = Stage;
4632 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4636 if (NULL != oldTexture) {
4637 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4638 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4640 IWineD3DBaseTexture_Release(oldTexture);
4641 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4642 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4643 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4646 if(bindCount && old->baseTexture.sampler == Stage) {
4648 /* Have to do a search for the other sampler(s) where the texture is bound to
4649 * Shouldn't happen as long as apps bind a texture only to one stage
4651 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4652 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4653 if(This->updateStateBlock->textures[i] == oldTexture) {
4654 old->baseTexture.sampler = i;
4661 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4666 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4667 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4669 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4671 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4672 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4675 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4676 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4677 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4680 *ppTexture=This->stateBlock->textures[Stage];
4682 IWineD3DBaseTexture_AddRef(*ppTexture);
4684 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4692 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4693 IWineD3DSurface **ppBackBuffer) {
4694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4695 IWineD3DSwapChain *swapChain;
4698 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4700 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4701 if (hr == WINED3D_OK) {
4702 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4703 IWineD3DSwapChain_Release(swapChain);
4705 *ppBackBuffer = NULL;
4710 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4711 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4712 WARN("(%p) : stub, calling idirect3d for now\n", This);
4713 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4716 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4717 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4718 IWineD3DSwapChain *swapChain;
4721 if(iSwapChain > 0) {
4722 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4723 if (hr == WINED3D_OK) {
4724 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4725 IWineD3DSwapChain_Release(swapChain);
4727 FIXME("(%p) Error getting display mode\n", This);
4730 /* Don't read the real display mode,
4731 but return the stored mode instead. X11 can't change the color
4732 depth, and some apps are pretty angry if they SetDisplayMode from
4733 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4735 Also don't relay to the swapchain because with ddraw it's possible
4736 that there isn't a swapchain at all */
4737 pMode->Width = This->ddraw_width;
4738 pMode->Height = This->ddraw_height;
4739 pMode->Format = This->ddraw_format;
4740 pMode->RefreshRate = 0;
4747 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4749 TRACE("(%p)->(%p)\n", This, hWnd);
4751 if(This->ddraw_fullscreen) {
4752 if(This->ddraw_window && This->ddraw_window != hWnd) {
4753 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4755 if(hWnd && This->ddraw_window != hWnd) {
4756 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4760 This->ddraw_window = hWnd;
4764 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4766 TRACE("(%p)->(%p)\n", This, hWnd);
4768 *hWnd = This->ddraw_window;
4773 * Stateblock related functions
4776 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4777 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4778 IWineD3DStateBlockImpl *object;
4779 HRESULT temp_result;
4782 TRACE("(%p)\n", This);
4784 if (This->isRecordingState) {
4785 return WINED3DERR_INVALIDCALL;
4788 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4789 if (NULL == object ) {
4790 FIXME("(%p)Error allocating memory for stateblock\n", This);
4791 return E_OUTOFMEMORY;
4793 TRACE("(%p) created object %p\n", This, object);
4794 object->wineD3DDevice= This;
4795 /** FIXME: object->parent = parent; **/
4796 object->parent = NULL;
4797 object->blockType = WINED3DSBT_RECORDED;
4799 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4801 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4802 list_init(&object->lightMap[i]);
4805 temp_result = allocate_shader_constants(object);
4806 if (WINED3D_OK != temp_result)
4809 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4810 This->updateStateBlock = object;
4811 This->isRecordingState = TRUE;
4813 TRACE("(%p) recording stateblock %p\n",This , object);
4817 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4818 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4820 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4822 if (!This->isRecordingState) {
4823 FIXME("(%p) not recording! returning error\n", This);
4824 *ppStateBlock = NULL;
4825 return WINED3DERR_INVALIDCALL;
4828 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4829 if(object->changed.renderState[i]) {
4830 object->contained_render_states[object->num_contained_render_states] = i;
4831 object->num_contained_render_states++;
4834 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4835 if(object->changed.transform[i]) {
4836 object->contained_transform_states[object->num_contained_transform_states] = i;
4837 object->num_contained_transform_states++;
4840 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4841 if(object->changed.vertexShaderConstantsF[i]) {
4842 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4843 object->num_contained_vs_consts_f++;
4846 for(i = 0; i < MAX_CONST_I; i++) {
4847 if(object->changed.vertexShaderConstantsI[i]) {
4848 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4849 object->num_contained_vs_consts_i++;
4852 for(i = 0; i < MAX_CONST_B; i++) {
4853 if(object->changed.vertexShaderConstantsB[i]) {
4854 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4855 object->num_contained_vs_consts_b++;
4858 for(i = 0; i < MAX_CONST_I; i++) {
4859 if(object->changed.pixelShaderConstantsI[i]) {
4860 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4861 object->num_contained_ps_consts_i++;
4864 for(i = 0; i < MAX_CONST_B; i++) {
4865 if(object->changed.pixelShaderConstantsB[i]) {
4866 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4867 object->num_contained_ps_consts_b++;
4870 for(i = 0; i < MAX_TEXTURES; i++) {
4871 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4872 if(object->changed.textureState[i][j]) {
4873 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4874 object->contained_tss_states[object->num_contained_tss_states].state = j;
4875 object->num_contained_tss_states++;
4879 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4880 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4881 if(object->changed.samplerState[i][j]) {
4882 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4883 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4884 object->num_contained_sampler_states++;
4889 *ppStateBlock = (IWineD3DStateBlock*) object;
4890 This->isRecordingState = FALSE;
4891 This->updateStateBlock = This->stateBlock;
4892 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4893 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4894 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4899 * Scene related functions
4901 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4902 /* At the moment we have no need for any functionality at the beginning
4904 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4905 TRACE("(%p)\n", This);
4908 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4909 return WINED3DERR_INVALIDCALL;
4911 This->inScene = TRUE;
4915 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4916 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4917 TRACE("(%p)\n", This);
4919 if(!This->inScene) {
4920 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4921 return WINED3DERR_INVALIDCALL;
4924 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4925 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4928 checkGLcall("glFlush");
4931 This->inScene = FALSE;
4935 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4936 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4937 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 IWineD3DSwapChain *swapChain = NULL;
4941 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4943 TRACE("(%p) Presenting the frame\n", This);
4945 for(i = 0 ; i < swapchains ; i ++) {
4947 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4948 TRACE("presentinng chain %d, %p\n", i, swapChain);
4949 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4950 IWineD3DSwapChain_Release(swapChain);
4956 /* Not called from the VTable (internal subroutine) */
4957 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4958 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4959 float Z, DWORD Stencil) {
4960 GLbitfield glMask = 0;
4962 WINED3DRECT curRect;
4964 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4965 UINT drawable_width, drawable_height;
4966 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4968 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4969 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4970 * for the cleared parts, and the untouched parts.
4972 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4973 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4974 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4975 * checking all this if the dest surface is in the drawable anyway.
4977 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4979 if(vp->X != 0 || vp->Y != 0 ||
4980 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4981 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4984 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4985 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4986 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4987 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4988 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4991 if(Count > 0 && pRects && (
4992 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4993 pRects[0].x2 < target->currentDesc.Width ||
4994 pRects[0].y2 < target->currentDesc.Height)) {
4995 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5002 target->get_drawable_size(target, &drawable_width, &drawable_height);
5004 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5007 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5008 apply_fbo_state((IWineD3DDevice *) This);
5011 /* Only set the values up once, as they are not changing */
5012 if (Flags & WINED3DCLEAR_STENCIL) {
5013 glClearStencil(Stencil);
5014 checkGLcall("glClearStencil");
5015 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5016 glStencilMask(0xFFFFFFFF);
5019 if (Flags & WINED3DCLEAR_ZBUFFER) {
5020 glDepthMask(GL_TRUE);
5022 checkGLcall("glClearDepth");
5023 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5024 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5026 if(This->depth_copy_state == WINED3D_DCS_COPY) {
5027 if(vp->X != 0 || vp->Y != 0 ||
5028 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5029 depth_copy((IWineD3DDevice *) This);
5031 else if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5032 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5033 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5034 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5035 depth_copy((IWineD3DDevice *) This);
5037 else if(Count > 0 && pRects && (
5038 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5039 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5040 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5041 depth_copy((IWineD3DDevice *) This);
5044 This->depth_copy_state = WINED3D_DCS_INITIAL;
5047 if (Flags & WINED3DCLEAR_TARGET) {
5048 TRACE("Clearing screen with glClear to color %x\n", Color);
5049 glClearColor(D3DCOLOR_R(Color),
5053 checkGLcall("glClearColor");
5055 /* Clear ALL colors! */
5056 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5057 glMask = glMask | GL_COLOR_BUFFER_BIT;
5060 vp_rect.left = vp->X;
5061 vp_rect.top = vp->Y;
5062 vp_rect.right = vp->X + vp->Width;
5063 vp_rect.bottom = vp->Y + vp->Height;
5064 if (!(Count > 0 && pRects)) {
5065 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5066 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5068 if(This->render_offscreen) {
5069 glScissor(vp_rect.left, vp_rect.top,
5070 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5072 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5073 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5075 checkGLcall("glScissor");
5077 checkGLcall("glClear");
5079 /* Now process each rect in turn */
5080 for (i = 0; i < Count; i++) {
5081 /* Note gl uses lower left, width/height */
5082 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5083 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5084 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5086 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5087 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5088 curRect.x1, (target->currentDesc.Height - curRect.y2),
5089 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5091 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5092 * The rectangle is not cleared, no error is returned, but further rectanlges are
5093 * still cleared if they are valid
5095 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5096 TRACE("Rectangle with negative dimensions, ignoring\n");
5100 if(This->render_offscreen) {
5101 glScissor(curRect.x1, curRect.y1,
5102 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5104 glScissor(curRect.x1, drawable_height - curRect.y2,
5105 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5107 checkGLcall("glScissor");
5110 checkGLcall("glClear");
5114 /* Restore the old values (why..?) */
5115 if (Flags & WINED3DCLEAR_STENCIL) {
5116 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5118 if (Flags & WINED3DCLEAR_TARGET) {
5119 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5120 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5121 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5122 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5123 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5125 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5126 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5128 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5129 /* TODO: Move the fbo logic into ModifyLocation() */
5130 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5131 target->Flags |= SFLAG_INTEXTURE;
5139 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5140 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5142 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5144 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5145 Count, pRects, Flags, Color, Z, Stencil);
5147 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5148 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5149 /* TODO: What about depth stencil buffers without stencil bits? */
5150 return WINED3DERR_INVALIDCALL;
5153 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5159 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5160 UINT PrimitiveCount) {
5162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5164 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5165 debug_d3dprimitivetype(PrimitiveType),
5166 StartVertex, PrimitiveCount);
5168 if(!This->stateBlock->vertexDecl) {
5169 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5170 return WINED3DERR_INVALIDCALL;
5173 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5174 if(This->stateBlock->streamIsUP) {
5175 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5176 This->stateBlock->streamIsUP = FALSE;
5179 if(This->stateBlock->loadBaseVertexIndex != 0) {
5180 This->stateBlock->loadBaseVertexIndex = 0;
5181 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5183 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5184 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5185 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5189 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5190 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5191 WINED3DPRIMITIVETYPE PrimitiveType,
5192 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5196 IWineD3DIndexBuffer *pIB;
5197 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5200 pIB = This->stateBlock->pIndexData;
5202 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5203 * without an index buffer set. (The first time at least...)
5204 * D3D8 simply dies, but I doubt it can do much harm to return
5205 * D3DERR_INVALIDCALL there as well. */
5206 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5207 return WINED3DERR_INVALIDCALL;
5210 if(!This->stateBlock->vertexDecl) {
5211 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5212 return WINED3DERR_INVALIDCALL;
5215 if(This->stateBlock->streamIsUP) {
5216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5217 This->stateBlock->streamIsUP = FALSE;
5219 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5221 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5222 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5223 minIndex, NumVertices, startIndex, primCount);
5225 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5226 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5232 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5233 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5237 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5238 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5243 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5244 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5245 UINT VertexStreamZeroStride) {
5246 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5247 IWineD3DVertexBuffer *vb;
5249 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5250 debug_d3dprimitivetype(PrimitiveType),
5251 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5253 if(!This->stateBlock->vertexDecl) {
5254 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5255 return WINED3DERR_INVALIDCALL;
5258 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5259 vb = This->stateBlock->streamSource[0];
5260 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5261 if(vb) IWineD3DVertexBuffer_Release(vb);
5262 This->stateBlock->streamOffset[0] = 0;
5263 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5264 This->stateBlock->streamIsUP = TRUE;
5265 This->stateBlock->loadBaseVertexIndex = 0;
5267 /* TODO: Only mark dirty if drawing from a different UP address */
5268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5270 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5271 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5273 /* MSDN specifies stream zero settings must be set to NULL */
5274 This->stateBlock->streamStride[0] = 0;
5275 This->stateBlock->streamSource[0] = NULL;
5277 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5278 * the new stream sources or use UP drawing again
5283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5284 UINT MinVertexIndex, UINT NumVertices,
5285 UINT PrimitiveCount, CONST void* pIndexData,
5286 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5287 UINT VertexStreamZeroStride) {
5289 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5290 IWineD3DVertexBuffer *vb;
5291 IWineD3DIndexBuffer *ib;
5293 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5294 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5295 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5296 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5298 if(!This->stateBlock->vertexDecl) {
5299 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5300 return WINED3DERR_INVALIDCALL;
5303 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5309 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5310 vb = This->stateBlock->streamSource[0];
5311 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5312 if(vb) IWineD3DVertexBuffer_Release(vb);
5313 This->stateBlock->streamIsUP = TRUE;
5314 This->stateBlock->streamOffset[0] = 0;
5315 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5317 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5318 This->stateBlock->baseVertexIndex = 0;
5319 This->stateBlock->loadBaseVertexIndex = 0;
5320 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5322 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5324 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5326 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5327 This->stateBlock->streamSource[0] = NULL;
5328 This->stateBlock->streamStride[0] = 0;
5329 ib = This->stateBlock->pIndexData;
5331 IWineD3DIndexBuffer_Release(ib);
5332 This->stateBlock->pIndexData = NULL;
5334 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5335 * SetStreamSource to specify a vertex buffer
5341 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5344 /* Mark the state dirty until we have nicer tracking
5345 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5349 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5350 This->stateBlock->baseVertexIndex = 0;
5351 This->up_strided = DrawPrimStrideData;
5352 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5353 This->up_strided = NULL;
5357 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5359 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5361 /* Mark the state dirty until we have nicer tracking
5362 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5365 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5367 This->stateBlock->streamIsUP = TRUE;
5368 This->stateBlock->baseVertexIndex = 0;
5369 This->up_strided = DrawPrimStrideData;
5370 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5371 This->up_strided = NULL;
5375 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5376 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5377 * not callable by the app directly no parameter validation checks are needed here.
5379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5380 WINED3DLOCKED_BOX src;
5381 WINED3DLOCKED_BOX dst;
5383 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5385 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5386 * dirtification to improve loading performance.
5388 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5389 if(FAILED(hr)) return hr;
5390 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5392 IWineD3DVolume_UnlockBox(pSourceVolume);
5396 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5398 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5400 IWineD3DVolume_UnlockBox(pSourceVolume);
5402 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5407 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5408 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5409 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5410 HRESULT hr = WINED3D_OK;
5411 WINED3DRESOURCETYPE sourceType;
5412 WINED3DRESOURCETYPE destinationType;
5415 /* TODO: think about moving the code into IWineD3DBaseTexture */
5417 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5419 /* verify that the source and destination textures aren't NULL */
5420 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5421 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5422 This, pSourceTexture, pDestinationTexture);
5423 hr = WINED3DERR_INVALIDCALL;
5426 if (pSourceTexture == pDestinationTexture) {
5427 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5428 This, pSourceTexture, pDestinationTexture);
5429 hr = WINED3DERR_INVALIDCALL;
5431 /* Verify that the source and destination textures are the same type */
5432 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5433 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5435 if (sourceType != destinationType) {
5436 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5438 hr = WINED3DERR_INVALIDCALL;
5441 /* check that both textures have the identical numbers of levels */
5442 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5443 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5444 hr = WINED3DERR_INVALIDCALL;
5447 if (WINED3D_OK == hr) {
5449 /* Make sure that the destination texture is loaded */
5450 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5452 /* Update every surface level of the texture */
5453 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5455 switch (sourceType) {
5456 case WINED3DRTYPE_TEXTURE:
5458 IWineD3DSurface *srcSurface;
5459 IWineD3DSurface *destSurface;
5461 for (i = 0 ; i < levels ; ++i) {
5462 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5463 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5464 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5465 IWineD3DSurface_Release(srcSurface);
5466 IWineD3DSurface_Release(destSurface);
5467 if (WINED3D_OK != hr) {
5468 WARN("(%p) : Call to update surface failed\n", This);
5474 case WINED3DRTYPE_CUBETEXTURE:
5476 IWineD3DSurface *srcSurface;
5477 IWineD3DSurface *destSurface;
5478 WINED3DCUBEMAP_FACES faceType;
5480 for (i = 0 ; i < levels ; ++i) {
5481 /* Update each cube face */
5482 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5483 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5484 if (WINED3D_OK != hr) {
5485 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5487 TRACE("Got srcSurface %p\n", srcSurface);
5489 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5490 if (WINED3D_OK != hr) {
5491 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5493 TRACE("Got desrSurface %p\n", destSurface);
5495 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5496 IWineD3DSurface_Release(srcSurface);
5497 IWineD3DSurface_Release(destSurface);
5498 if (WINED3D_OK != hr) {
5499 WARN("(%p) : Call to update surface failed\n", This);
5507 case WINED3DRTYPE_VOLUMETEXTURE:
5509 IWineD3DVolume *srcVolume = NULL;
5510 IWineD3DVolume *destVolume = NULL;
5512 for (i = 0 ; i < levels ; ++i) {
5513 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5514 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5515 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5516 IWineD3DVolume_Release(srcVolume);
5517 IWineD3DVolume_Release(destVolume);
5518 if (WINED3D_OK != hr) {
5519 WARN("(%p) : Call to update volume failed\n", This);
5527 FIXME("(%p) : Unsupported source and destination type\n", This);
5528 hr = WINED3DERR_INVALIDCALL;
5535 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5536 IWineD3DSwapChain *swapChain;
5538 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5539 if(hr == WINED3D_OK) {
5540 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5541 IWineD3DSwapChain_Release(swapChain);
5546 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5548 /* return a sensible default */
5550 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5551 FIXME("(%p) : stub\n", This);
5555 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5559 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5560 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5561 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5562 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5567 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5571 PALETTEENTRY **palettes;
5573 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5575 if (PaletteNumber >= MAX_PALETTES) {
5576 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5577 return WINED3DERR_INVALIDCALL;
5580 if (PaletteNumber >= This->NumberOfPalettes) {
5581 NewSize = This->NumberOfPalettes;
5584 } while(PaletteNumber >= NewSize);
5585 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5587 ERR("Out of memory!\n");
5588 return E_OUTOFMEMORY;
5590 This->palettes = palettes;
5591 This->NumberOfPalettes = NewSize;
5594 if (!This->palettes[PaletteNumber]) {
5595 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5596 if (!This->palettes[PaletteNumber]) {
5597 ERR("Out of memory!\n");
5598 return E_OUTOFMEMORY;
5602 for (j = 0; j < 256; ++j) {
5603 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5604 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5605 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5606 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5608 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5609 TRACE("(%p) : returning\n", This);
5613 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5614 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5616 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5617 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5618 /* What happens in such situation isn't documented; Native seems to silently abort
5619 on such conditions. Return Invalid Call. */
5620 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5621 return WINED3DERR_INVALIDCALL;
5623 for (j = 0; j < 256; ++j) {
5624 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5625 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5626 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5627 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5629 TRACE("(%p) : returning\n", This);
5633 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5635 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5636 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5637 (tested with reference rasterizer). Return Invalid Call. */
5638 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5639 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5640 return WINED3DERR_INVALIDCALL;
5642 /*TODO: stateblocks */
5643 if (This->currentPalette != PaletteNumber) {
5644 This->currentPalette = PaletteNumber;
5645 dirtify_p8_texture_samplers(This);
5647 TRACE("(%p) : returning\n", This);
5651 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5653 if (PaletteNumber == NULL) {
5654 WARN("(%p) : returning Invalid Call\n", This);
5655 return WINED3DERR_INVALIDCALL;
5657 /*TODO: stateblocks */
5658 *PaletteNumber = This->currentPalette;
5659 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5663 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5665 static BOOL showFixmes = TRUE;
5667 FIXME("(%p) : stub\n", This);
5671 This->softwareVertexProcessing = bSoftware;
5676 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 static BOOL showFixmes = TRUE;
5680 FIXME("(%p) : stub\n", This);
5683 return This->softwareVertexProcessing;
5687 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5689 IWineD3DSwapChain *swapChain;
5692 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5694 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5695 if(hr == WINED3D_OK){
5696 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5697 IWineD3DSwapChain_Release(swapChain);
5699 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5705 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 static BOOL showfixmes = TRUE;
5708 if(nSegments != 0.0f) {
5710 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5717 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5719 static BOOL showfixmes = TRUE;
5721 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5727 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5729 /** TODO: remove casts to IWineD3DSurfaceImpl
5730 * NOTE: move code to surface to accomplish this
5731 ****************************************/
5732 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5733 int srcWidth, srcHeight;
5734 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5735 WINED3DFORMAT destFormat, srcFormat;
5737 int srcLeft, destLeft, destTop;
5738 WINED3DPOOL srcPool, destPool;
5740 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5741 glDescriptor *glDescription = NULL;
5744 CONVERT_TYPES convert = NO_CONVERSION;
5746 WINED3DSURFACE_DESC winedesc;
5748 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5749 memset(&winedesc, 0, sizeof(winedesc));
5750 winedesc.Width = &srcSurfaceWidth;
5751 winedesc.Height = &srcSurfaceHeight;
5752 winedesc.Pool = &srcPool;
5753 winedesc.Format = &srcFormat;
5755 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5757 winedesc.Width = &destSurfaceWidth;
5758 winedesc.Height = &destSurfaceHeight;
5759 winedesc.Pool = &destPool;
5760 winedesc.Format = &destFormat;
5761 winedesc.Size = &destSize;
5763 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5765 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5766 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5767 return WINED3DERR_INVALIDCALL;
5770 /* This call loads the opengl surface directly, instead of copying the surface to the
5771 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5772 * copy in sysmem and use regular surface loading.
5774 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5775 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5776 if(convert != NO_CONVERSION) {
5777 return IWineD3DSurface_BltFast(pDestinationSurface,
5778 pDestPoint ? pDestPoint->x : 0,
5779 pDestPoint ? pDestPoint->y : 0,
5780 pSourceSurface, (RECT *) pSourceRect, 0);
5783 if (destFormat == WINED3DFMT_UNKNOWN) {
5784 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5785 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5787 /* Get the update surface description */
5788 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5791 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5795 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5796 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5797 checkGLcall("glActiveTextureARB");
5800 /* Make sure the surface is loaded and up to date */
5801 IWineD3DSurface_PreLoad(pDestinationSurface);
5803 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5805 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5806 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5807 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5808 srcLeft = pSourceRect ? pSourceRect->left : 0;
5809 destLeft = pDestPoint ? pDestPoint->x : 0;
5810 destTop = pDestPoint ? pDestPoint->y : 0;
5813 /* This function doesn't support compressed textures
5814 the pitch is just bytesPerPixel * width */
5815 if(srcWidth != srcSurfaceWidth || srcLeft ){
5816 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5817 offset += srcLeft * pSrcSurface->bytesPerPixel;
5818 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5820 /* TODO DXT formats */
5822 if(pSourceRect != NULL && pSourceRect->top != 0){
5823 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5825 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5827 ,glDescription->level
5832 ,glDescription->glFormat
5833 ,glDescription->glType
5834 ,IWineD3DSurface_GetData(pSourceSurface)
5838 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5840 /* need to lock the surface to get the data */
5841 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5844 /* TODO: Cube and volume support */
5846 /* not a whole row so we have to do it a line at a time */
5849 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5850 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5852 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5854 glTexSubImage2D(glDescription->target
5855 ,glDescription->level
5860 ,glDescription->glFormat
5861 ,glDescription->glType
5862 ,data /* could be quicker using */
5867 } else { /* Full width, so just write out the whole texture */
5869 if (WINED3DFMT_DXT1 == destFormat ||
5870 WINED3DFMT_DXT2 == destFormat ||
5871 WINED3DFMT_DXT3 == destFormat ||
5872 WINED3DFMT_DXT4 == destFormat ||
5873 WINED3DFMT_DXT5 == destFormat) {
5874 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5875 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5876 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5877 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5878 } if (destFormat != srcFormat) {
5879 FIXME("Updating mixed format compressed texture is not curretly support\n");
5881 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5882 glDescription->level,
5883 glDescription->glFormatInternal,
5888 IWineD3DSurface_GetData(pSourceSurface));
5891 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5896 glTexSubImage2D(glDescription->target
5897 ,glDescription->level
5902 ,glDescription->glFormat
5903 ,glDescription->glType
5904 ,IWineD3DSurface_GetData(pSourceSurface)
5908 checkGLcall("glTexSubImage2D");
5912 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5913 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(0));
5918 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5920 struct WineD3DRectPatch *patch;
5924 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5926 if(!(Handle || pRectPatchInfo)) {
5927 /* TODO: Write a test for the return value, thus the FIXME */
5928 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5929 return WINED3DERR_INVALIDCALL;
5933 i = PATCHMAP_HASHFUNC(Handle);
5935 LIST_FOR_EACH(e, &This->patches[i]) {
5936 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5937 if(patch->Handle == Handle) {
5944 TRACE("Patch does not exist. Creating a new one\n");
5945 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5946 patch->Handle = Handle;
5947 list_add_head(&This->patches[i], &patch->entry);
5949 TRACE("Found existing patch %p\n", patch);
5952 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5953 * attributes we have to tesselate, read back, and draw. This needs a patch
5954 * management structure instance. Create one.
5956 * A possible improvement is to check if a vertex shader is used, and if not directly
5959 FIXME("Drawing an uncached patch. This is slow\n");
5960 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5963 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5964 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5965 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5967 TRACE("Tesselation density or patch info changed, retesselating\n");
5969 if(pRectPatchInfo) {
5970 patch->RectPatchInfo = *pRectPatchInfo;
5972 patch->numSegs[0] = pNumSegs[0];
5973 patch->numSegs[1] = pNumSegs[1];
5974 patch->numSegs[2] = pNumSegs[2];
5975 patch->numSegs[3] = pNumSegs[3];
5977 hr = tesselate_rectpatch(This, patch);
5979 WARN("Patch tesselation failed\n");
5981 /* Do not release the handle to store the params of the patch */
5983 HeapFree(GetProcessHeap(), 0, patch);
5989 This->currentPatch = patch;
5990 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5991 This->currentPatch = NULL;
5993 /* Destroy uncached patches */
5995 HeapFree(GetProcessHeap(), 0, patch->mem);
5996 HeapFree(GetProcessHeap(), 0, patch);
6001 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6002 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6003 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6004 FIXME("(%p) : Stub\n", This);
6008 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6011 struct WineD3DRectPatch *patch;
6013 TRACE("(%p) Handle(%d)\n", This, Handle);
6015 i = PATCHMAP_HASHFUNC(Handle);
6016 LIST_FOR_EACH(e, &This->patches[i]) {
6017 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6018 if(patch->Handle == Handle) {
6019 TRACE("Deleting patch %p\n", patch);
6020 list_remove(&patch->entry);
6021 HeapFree(GetProcessHeap(), 0, patch->mem);
6022 HeapFree(GetProcessHeap(), 0, patch);
6027 /* TODO: Write a test for the return value */
6028 FIXME("Attempt to destroy nonexistent patch\n");
6029 return WINED3DERR_INVALIDCALL;
6032 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6034 IWineD3DSwapChain *swapchain;
6036 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6037 if (SUCCEEDED(hr)) {
6038 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6045 static void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6049 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6050 checkGLcall("glGenFramebuffersEXT()");
6052 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6053 checkGLcall("glBindFramebuffer()");
6056 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6057 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6058 IWineD3DBaseTextureImpl *texture_impl;
6059 GLenum texttarget, target;
6062 texttarget = surface_impl->glDescription.target;
6063 if(texttarget == GL_TEXTURE_2D) {
6064 target = GL_TEXTURE_2D;
6065 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6066 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6067 target = GL_TEXTURE_RECTANGLE_ARB;
6068 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6070 target = GL_TEXTURE_CUBE_MAP_ARB;
6071 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6074 IWineD3DSurface_PreLoad(surface);
6076 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6077 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6078 glBindTexture(target, old_binding);
6080 /* Update base texture states array */
6081 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6082 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6083 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6084 if (texture_impl->baseTexture.bindCount) {
6085 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6088 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6091 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6092 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6094 checkGLcall("attach_surface_fbo");
6097 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6098 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6099 IWineD3DSwapChain *swapchain;
6101 swapchain = get_swapchain(surface);
6105 TRACE("Surface %p is onscreen\n", surface);
6107 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6108 buffer = surface_get_gl_buffer(surface, swapchain);
6109 glDrawBuffer(buffer);
6110 checkGLcall("glDrawBuffer()");
6112 TRACE("Surface %p is offscreen\n", surface);
6113 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6114 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6118 glEnable(GL_SCISSOR_TEST);
6120 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6122 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6123 rect->x2 - rect->x1, rect->y2 - rect->y1);
6125 checkGLcall("glScissor");
6127 glDisable(GL_SCISSOR_TEST);
6129 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6131 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6134 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6135 glClear(GL_COLOR_BUFFER_BIT);
6136 checkGLcall("glClear");
6138 if (This->render_offscreen) {
6139 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6141 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6142 checkGLcall("glBindFramebuffer()");
6145 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6146 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6147 glDrawBuffer(GL_BACK);
6148 checkGLcall("glDrawBuffer()");
6152 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6153 unsigned int r, g, b, a;
6156 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6157 destfmt == WINED3DFMT_R8G8B8)
6160 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6162 a = (color & 0xff000000) >> 24;
6163 r = (color & 0x00ff0000) >> 16;
6164 g = (color & 0x0000ff00) >> 8;
6165 b = (color & 0x000000ff) >> 0;
6169 case WINED3DFMT_R5G6B5:
6170 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6177 TRACE("Returning %08x\n", ret);
6180 case WINED3DFMT_X1R5G5B5:
6181 case WINED3DFMT_A1R5G5B5:
6190 TRACE("Returning %08x\n", ret);
6194 TRACE("Returning %08x\n", a);
6197 case WINED3DFMT_X4R4G4B4:
6198 case WINED3DFMT_A4R4G4B4:
6207 TRACE("Returning %08x\n", ret);
6210 case WINED3DFMT_R3G3B2:
6217 TRACE("Returning %08x\n", ret);
6220 case WINED3DFMT_X8B8G8R8:
6221 case WINED3DFMT_A8B8G8R8:
6226 TRACE("Returning %08x\n", ret);
6229 case WINED3DFMT_A2R10G10B10:
6231 r = (r * 1024) / 256;
6232 g = (g * 1024) / 256;
6233 b = (b * 1024) / 256;
6238 TRACE("Returning %08x\n", ret);
6241 case WINED3DFMT_A2B10G10R10:
6243 r = (r * 1024) / 256;
6244 g = (g * 1024) / 256;
6245 b = (b * 1024) / 256;
6250 TRACE("Returning %08x\n", ret);
6254 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6259 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6260 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6261 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6263 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6265 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6266 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6267 return WINED3DERR_INVALIDCALL;
6270 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6272 color_fill_fbo(iface, pSurface, pRect, color);
6276 /* Just forward this to the DirectDraw blitting engine */
6277 memset(&BltFx, 0, sizeof(BltFx));
6278 BltFx.dwSize = sizeof(BltFx);
6279 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6280 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6284 /* rendertarget and depth stencil functions */
6285 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6288 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6289 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6290 return WINED3DERR_INVALIDCALL;
6293 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6294 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6295 /* Note inc ref on returned surface */
6296 if(*ppRenderTarget != NULL)
6297 IWineD3DSurface_AddRef(*ppRenderTarget);
6301 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6303 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6304 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6305 IWineD3DSwapChainImpl *Swapchain;
6308 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6310 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6311 if(hr != WINED3D_OK) {
6312 ERR("Can't get the swapchain\n");
6316 /* Make sure to release the swapchain */
6317 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6319 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6320 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6321 return WINED3DERR_INVALIDCALL;
6323 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6324 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6325 return WINED3DERR_INVALIDCALL;
6328 if(Swapchain->frontBuffer != Front) {
6329 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6331 if(Swapchain->frontBuffer)
6332 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6333 Swapchain->frontBuffer = Front;
6335 if(Swapchain->frontBuffer) {
6336 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6340 if(Back && !Swapchain->backBuffer) {
6341 /* We need memory for the back buffer array - only one back buffer this way */
6342 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6343 if(!Swapchain->backBuffer) {
6344 ERR("Out of memory\n");
6345 return E_OUTOFMEMORY;
6349 if(Swapchain->backBuffer[0] != Back) {
6350 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6352 /* What to do about the context here in the case of multithreading? Not sure.
6353 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6356 if(!Swapchain->backBuffer[0]) {
6357 /* GL was told to draw to the front buffer at creation,
6360 glDrawBuffer(GL_BACK);
6361 checkGLcall("glDrawBuffer(GL_BACK)");
6362 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6363 Swapchain->presentParms.BackBufferCount = 1;
6365 /* That makes problems - disable for now */
6366 /* glDrawBuffer(GL_FRONT); */
6367 checkGLcall("glDrawBuffer(GL_FRONT)");
6368 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6369 Swapchain->presentParms.BackBufferCount = 0;
6373 if(Swapchain->backBuffer[0])
6374 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6375 Swapchain->backBuffer[0] = Back;
6377 if(Swapchain->backBuffer[0]) {
6378 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6380 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6381 Swapchain->backBuffer = NULL;
6389 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6391 *ppZStencilSurface = This->stencilBufferTarget;
6392 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6394 if(*ppZStencilSurface != NULL) {
6395 /* Note inc ref on returned surface */
6396 IWineD3DSurface_AddRef(*ppZStencilSurface);
6399 return WINED3DERR_NOTFOUND;
6403 /* TODO: Handle stencil attachments */
6404 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6406 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6408 TRACE("Set depth stencil to %p\n", depth_stencil);
6410 if (depth_stencil_impl) {
6411 if (depth_stencil_impl->current_renderbuffer) {
6412 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6413 checkGLcall("glFramebufferRenderbufferEXT()");
6415 IWineD3DBaseTextureImpl *texture_impl;
6416 GLenum texttarget, target;
6417 GLint old_binding = 0;
6419 texttarget = depth_stencil_impl->glDescription.target;
6420 if(texttarget == GL_TEXTURE_2D) {
6421 target = GL_TEXTURE_2D;
6422 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6423 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6424 target = GL_TEXTURE_RECTANGLE_ARB;
6425 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6427 target = GL_TEXTURE_CUBE_MAP_ARB;
6428 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6431 IWineD3DSurface_PreLoad(depth_stencil);
6433 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6434 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6435 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6436 glBindTexture(target, old_binding);
6438 /* Update base texture states array */
6439 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6440 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6441 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6442 if (texture_impl->baseTexture.bindCount) {
6443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6446 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6449 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6450 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6451 checkGLcall("glFramebufferTexture2DEXT()");
6454 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6455 checkGLcall("glFramebufferTexture2DEXT()");
6459 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6461 IWineD3DSurfaceImpl *rtimpl = (IWineD3DSurfaceImpl *)render_target;
6463 TRACE("Set render target %u to %p\n", idx, render_target);
6466 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6467 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6469 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6470 checkGLcall("glFramebufferTexture2DEXT()");
6472 This->draw_buffers[idx] = GL_NONE;
6476 static void check_fbo_status(IWineD3DDevice *iface) {
6477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6480 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6481 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6482 TRACE("FBO complete\n");
6484 IWineD3DSurfaceImpl *attachment;
6486 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6488 /* Dump the FBO attachments */
6489 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6490 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6492 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6493 attachment->pow2Width, attachment->pow2Height);
6496 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6498 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6499 attachment->pow2Width, attachment->pow2Height);
6504 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6505 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6506 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6507 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6509 if (!ds_impl) return FALSE;
6511 if (ds_impl->current_renderbuffer) {
6512 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6513 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6516 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6517 rt_impl->pow2Height != ds_impl->pow2Height);
6520 void apply_fbo_state(IWineD3DDevice *iface) {
6521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6524 if (This->render_offscreen) {
6525 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6527 /* Apply render targets */
6528 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6529 IWineD3DSurface *render_target = This->render_targets[i];
6530 if (This->fbo_color_attachments[i] != render_target) {
6531 set_render_target_fbo(iface, i, render_target);
6532 This->fbo_color_attachments[i] = render_target;
6536 /* Apply depth targets */
6537 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6538 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6539 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6541 if (This->stencilBufferTarget) {
6542 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6544 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6545 This->fbo_depth_attachment = This->stencilBufferTarget;
6548 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6549 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6550 checkGLcall("glDrawBuffers()");
6552 glDrawBuffer(This->draw_buffers[0]);
6553 checkGLcall("glDrawBuffer()");
6556 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6559 check_fbo_status(iface);
6562 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6563 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6565 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6566 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6569 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6570 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6571 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6572 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6575 case WINED3DTEXF_LINEAR:
6576 gl_filter = GL_LINEAR;
6580 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6581 case WINED3DTEXF_NONE:
6582 case WINED3DTEXF_POINT:
6583 gl_filter = GL_NEAREST;
6587 /* Attach src surface to src fbo */
6588 src_swapchain = get_swapchain(src_surface);
6589 if (src_swapchain) {
6592 TRACE("Source surface %p is onscreen\n", src_surface);
6593 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6594 /* Make sure the drawable is up to date. In the offscreen case
6595 * attach_surface_fbo() implicitly takes care of this. */
6596 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6599 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6600 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6601 glReadBuffer(buffer);
6602 checkGLcall("glReadBuffer()");
6604 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6605 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6607 TRACE("Source surface %p is offscreen\n", src_surface);
6609 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6610 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6611 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6612 checkGLcall("glReadBuffer()");
6616 /* Attach dst surface to dst fbo */
6617 dst_swapchain = get_swapchain(dst_surface);
6618 if (dst_swapchain) {
6621 TRACE("Destination surface %p is onscreen\n", dst_surface);
6622 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6623 /* Make sure the drawable is up to date. In the offscreen case
6624 * attach_surface_fbo() implicitly takes care of this. */
6625 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6628 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6629 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6630 glDrawBuffer(buffer);
6631 checkGLcall("glDrawBuffer()");
6633 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6634 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6636 TRACE("Destination surface %p is offscreen\n", dst_surface);
6638 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6639 if(!src_swapchain) {
6640 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6644 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6645 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6646 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6647 checkGLcall("glDrawBuffer()");
6649 glDisable(GL_SCISSOR_TEST);
6650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6653 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6654 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6655 checkGLcall("glBlitFramebuffer()");
6657 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6658 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6659 checkGLcall("glBlitFramebuffer()");
6662 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6664 if (This->render_offscreen) {
6665 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6667 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6668 checkGLcall("glBindFramebuffer()");
6671 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6672 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6673 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6674 glDrawBuffer(GL_BACK);
6675 checkGLcall("glDrawBuffer()");
6680 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6682 WINED3DVIEWPORT viewport;
6684 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6686 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6687 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6688 This, RenderTargetIndex, GL_LIMITS(buffers));
6689 return WINED3DERR_INVALIDCALL;
6692 /* MSDN says that null disables the render target
6693 but a device must always be associated with a render target
6694 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6696 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6697 FIXME("Trying to set render target 0 to NULL\n");
6698 return WINED3DERR_INVALIDCALL;
6700 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6701 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);
6702 return WINED3DERR_INVALIDCALL;
6705 /* If we are trying to set what we already have, don't bother */
6706 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6707 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6710 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6711 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6712 This->render_targets[RenderTargetIndex] = pRenderTarget;
6714 /* Render target 0 is special */
6715 if(RenderTargetIndex == 0) {
6716 /* Finally, reset the viewport as the MSDN states. */
6717 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6718 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6721 viewport.MaxZ = 1.0f;
6722 viewport.MinZ = 0.0f;
6723 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6724 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6725 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6727 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6729 /* Activate the new render target for now. This shouldn't stay here, but is needed until all methods using gl activate the
6731 * Use resourceload usage, this will just set the drawables and context but not apply any states. The stateblock may be
6732 * incomplete or incorrect when SetRenderTarget is called. DrawPrim() will apply the states when it is called.
6734 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
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 maxamise 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 / depth stencil after the reset */
7050 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7053 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7054 TRACE("Unloading resource %p\n", resource);
7055 IWineD3DResource_UnLoad(resource);
7056 IWineD3DResource_Release(resource);
7060 static void reset_fbo_state(IWineD3DDevice *iface) {
7061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7065 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7066 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7069 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7072 if (This->src_fbo) {
7073 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7076 if (This->dst_fbo) {
7077 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7080 checkGLcall("Tear down fbos\n");
7083 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7084 This->fbo_color_attachments[i] = NULL;
7086 This->fbo_depth_attachment = NULL;
7089 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7091 WINED3DDISPLAYMODE m;
7094 /* All Windowed modes are supported, as is leaving the current mode */
7095 if(pp->Windowed) return TRUE;
7096 if(!pp->BackBufferWidth) return TRUE;
7097 if(!pp->BackBufferHeight) return TRUE;
7099 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7100 for(i = 0; i < count; i++) {
7101 memset(&m, 0, sizeof(m));
7102 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7104 ERR("EnumAdapterModes failed\n");
7106 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7107 /* Mode found, it is supported */
7111 /* Mode not found -> not supported */
7115 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7116 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7117 IWineD3DSwapChainImpl *swapchain;
7119 BOOL DisplayModeChanged = FALSE;
7120 WINED3DDISPLAYMODE mode;
7121 IWineD3DBaseShaderImpl *shader;
7122 IWineD3DSurfaceImpl *target;
7124 TRACE("(%p)\n", This);
7126 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7128 ERR("Failed to get the first implicit swapchain\n");
7132 if(!is_display_mode_supported(This, pPresentationParameters)) {
7133 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7134 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7135 pPresentationParameters->BackBufferHeight);
7136 return WINED3DERR_INVALIDCALL;
7139 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7140 * on an existing gl context, so there's no real need for recreation.
7142 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7144 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7146 TRACE("New params:\n");
7147 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7148 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7149 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7150 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7151 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7152 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7153 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7154 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7155 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7156 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7157 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7158 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7159 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7161 /* No special treatment of these parameters. Just store them */
7162 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7163 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7164 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7165 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7167 /* What to do about these? */
7168 if(pPresentationParameters->BackBufferCount != 0 &&
7169 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7170 ERR("Cannot change the back buffer count yet\n");
7172 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7173 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7174 ERR("Cannot change the back buffer format yet\n");
7176 if(pPresentationParameters->hDeviceWindow != NULL &&
7177 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7178 ERR("Cannot change the device window yet\n");
7180 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7181 ERR("What do do about a changed auto depth stencil parameter?\n");
7184 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7185 reset_fbo_state((IWineD3DDevice *) This);
7188 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7189 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7190 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7194 if(This->depth_blt_texture) {
7195 glDeleteTextures(1, &This->depth_blt_texture);
7196 This->depth_blt_texture = 0;
7198 This->shader_backend->shader_destroy_depth_blt(iface);
7199 This->shader_backend->shader_free_private(iface);
7201 for (i = 0; i < GL_LIMITS(textures); i++) {
7202 /* Textures are recreated below */
7203 glDeleteTextures(1, &This->dummyTextureName[i]);
7204 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7205 This->dummyTextureName[i] = 0;
7209 while(This->numContexts) {
7210 DestroyContext(This, This->contexts[0]);
7212 This->activeContext = NULL;
7213 HeapFree(GetProcessHeap(), 0, swapchain->context);
7214 swapchain->context = NULL;
7215 swapchain->num_contexts = 0;
7217 if(pPresentationParameters->Windowed) {
7218 mode.Width = swapchain->orig_width;
7219 mode.Height = swapchain->orig_height;
7220 mode.RefreshRate = 0;
7221 mode.Format = swapchain->presentParms.BackBufferFormat;
7223 mode.Width = pPresentationParameters->BackBufferWidth;
7224 mode.Height = pPresentationParameters->BackBufferHeight;
7225 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7226 mode.Format = swapchain->presentParms.BackBufferFormat;
7229 /* Should Width == 800 && Height == 0 set 800x600? */
7230 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7231 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7232 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7239 vp.Width = pPresentationParameters->BackBufferWidth;
7240 vp.Height = pPresentationParameters->BackBufferHeight;
7244 if(!pPresentationParameters->Windowed) {
7245 DisplayModeChanged = TRUE;
7247 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7248 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7250 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7251 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7252 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7254 if(This->auto_depth_stencil_buffer) {
7255 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7259 /* Now set the new viewport */
7260 IWineD3DDevice_SetViewport(iface, &vp);
7263 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7264 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7265 DisplayModeChanged) {
7267 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7268 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7269 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7270 } else if(!pPresentationParameters->Windowed) {
7271 DWORD style = This->style, exStyle = This->exStyle;
7272 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7273 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7274 * Reset to clear up their mess. Guild Wars also loses the device during that.
7278 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7279 This->style = style;
7280 This->exStyle = exStyle;
7283 /* Recreate the primary swapchain's context */
7284 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7285 if(swapchain->backBuffer) {
7286 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7288 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7290 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7291 &swapchain->presentParms);
7292 swapchain->num_contexts = 1;
7293 This->activeContext = swapchain->context[0];
7294 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7296 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7298 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7300 create_dummy_textures(This);
7303 hr = This->shader_backend->shader_alloc_private(iface);
7305 ERR("Failed to recreate shader private data\n");
7309 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7315 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7317 /** FIXME: always true at the moment **/
7318 if(!bEnableDialogs) {
7319 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7325 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7327 TRACE("(%p) : pParameters %p\n", This, pParameters);
7329 *pParameters = This->createParms;
7333 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7334 IWineD3DSwapChain *swapchain;
7335 HRESULT hrc = WINED3D_OK;
7337 TRACE("Relaying to swapchain\n");
7339 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7340 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7341 IWineD3DSwapChain_Release(swapchain);
7346 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7347 IWineD3DSwapChain *swapchain;
7348 HRESULT hrc = WINED3D_OK;
7350 TRACE("Relaying to swapchain\n");
7352 if ((hrc = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain)) == WINED3D_OK) {
7353 hrc =IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7354 IWineD3DSwapChain_Release(swapchain);
7360 /** ********************************************************
7361 * Notification functions
7362 ** ********************************************************/
7363 /** This function must be called in the release of a resource when ref == 0,
7364 * the contents of resource must still be correct,
7365 * any handles to other resource held by the caller must be closed
7366 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7367 *****************************************************/
7368 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7369 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7371 TRACE("(%p) : Adding Resource %p\n", This, resource);
7372 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7375 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7376 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7378 TRACE("(%p) : Removing resource %p\n", This, resource);
7380 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7384 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7388 TRACE("(%p) : resource %p\n", This, resource);
7389 switch(IWineD3DResource_GetType(resource)){
7390 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7391 case WINED3DRTYPE_SURFACE: {
7394 /* Cleanup any FBO attachments if d3d is enabled */
7395 if(This->d3d_initialized) {
7396 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7397 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7399 TRACE("Last active render target destroyed\n");
7400 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7401 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7402 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7403 * and the lastActiveRenderTarget member shouldn't matter
7406 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7407 TRACE("Activating primary back buffer\n");
7408 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7409 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7410 /* Single buffering environment */
7411 TRACE("Activating primary front buffer\n");
7412 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7414 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7415 /* Implicit render target destroyed, that means the device is being destroyed
7416 * whatever we set here, it shouldn't matter
7418 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7421 /* May happen during ddraw uninitialization */
7422 TRACE("Render target set, but swapchain does not exist!\n");
7423 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7428 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7429 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7430 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7431 set_render_target_fbo(iface, i, NULL);
7432 This->fbo_color_attachments[i] = NULL;
7435 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7436 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7437 set_depth_stencil_fbo(iface, NULL);
7438 This->fbo_depth_attachment = NULL;
7445 case WINED3DRTYPE_TEXTURE:
7446 case WINED3DRTYPE_CUBETEXTURE:
7447 case WINED3DRTYPE_VOLUMETEXTURE:
7448 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7449 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7450 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7451 This->stateBlock->textures[counter] = NULL;
7453 if (This->updateStateBlock != This->stateBlock ){
7454 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7455 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7456 This->updateStateBlock->textures[counter] = NULL;
7461 case WINED3DRTYPE_VOLUME:
7462 /* TODO: nothing really? */
7464 case WINED3DRTYPE_VERTEXBUFFER:
7465 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7468 TRACE("Cleaning up stream pointers\n");
7470 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7471 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7472 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7474 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7475 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7476 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7477 This->updateStateBlock->streamSource[streamNumber] = 0;
7478 /* Set changed flag? */
7481 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) */
7482 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7483 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7484 This->stateBlock->streamSource[streamNumber] = 0;
7487 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7488 else { /* This shouldn't happen */
7489 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7496 case WINED3DRTYPE_INDEXBUFFER:
7497 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7498 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7499 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7500 This->updateStateBlock->pIndexData = NULL;
7503 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7504 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7505 This->stateBlock->pIndexData = NULL;
7511 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7516 /* Remove the resource from the resourceStore */
7517 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7519 TRACE("Resource released\n");
7523 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7525 IWineD3DResourceImpl *resource, *cursor;
7527 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7529 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7530 TRACE("enumerating resource %p\n", resource);
7531 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7532 ret = pCallback((IWineD3DResource *) resource, pData);
7533 if(ret == S_FALSE) {
7534 TRACE("Canceling enumeration\n");
7541 /**********************************************************
7542 * IWineD3DDevice VTbl follows
7543 **********************************************************/
7545 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7547 /*** IUnknown methods ***/
7548 IWineD3DDeviceImpl_QueryInterface,
7549 IWineD3DDeviceImpl_AddRef,
7550 IWineD3DDeviceImpl_Release,
7551 /*** IWineD3DDevice methods ***/
7552 IWineD3DDeviceImpl_GetParent,
7553 /*** Creation methods**/
7554 IWineD3DDeviceImpl_CreateVertexBuffer,
7555 IWineD3DDeviceImpl_CreateIndexBuffer,
7556 IWineD3DDeviceImpl_CreateStateBlock,
7557 IWineD3DDeviceImpl_CreateSurface,
7558 IWineD3DDeviceImpl_CreateTexture,
7559 IWineD3DDeviceImpl_CreateVolumeTexture,
7560 IWineD3DDeviceImpl_CreateVolume,
7561 IWineD3DDeviceImpl_CreateCubeTexture,
7562 IWineD3DDeviceImpl_CreateQuery,
7563 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7564 IWineD3DDeviceImpl_CreateVertexDeclaration,
7565 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7566 IWineD3DDeviceImpl_CreateVertexShader,
7567 IWineD3DDeviceImpl_CreatePixelShader,
7568 IWineD3DDeviceImpl_CreatePalette,
7569 /*** Odd functions **/
7570 IWineD3DDeviceImpl_Init3D,
7571 IWineD3DDeviceImpl_Uninit3D,
7572 IWineD3DDeviceImpl_SetFullscreen,
7573 IWineD3DDeviceImpl_SetMultithreaded,
7574 IWineD3DDeviceImpl_EvictManagedResources,
7575 IWineD3DDeviceImpl_GetAvailableTextureMem,
7576 IWineD3DDeviceImpl_GetBackBuffer,
7577 IWineD3DDeviceImpl_GetCreationParameters,
7578 IWineD3DDeviceImpl_GetDeviceCaps,
7579 IWineD3DDeviceImpl_GetDirect3D,
7580 IWineD3DDeviceImpl_GetDisplayMode,
7581 IWineD3DDeviceImpl_SetDisplayMode,
7582 IWineD3DDeviceImpl_GetHWND,
7583 IWineD3DDeviceImpl_SetHWND,
7584 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7585 IWineD3DDeviceImpl_GetRasterStatus,
7586 IWineD3DDeviceImpl_GetSwapChain,
7587 IWineD3DDeviceImpl_Reset,
7588 IWineD3DDeviceImpl_SetDialogBoxMode,
7589 IWineD3DDeviceImpl_SetCursorProperties,
7590 IWineD3DDeviceImpl_SetCursorPosition,
7591 IWineD3DDeviceImpl_ShowCursor,
7592 IWineD3DDeviceImpl_TestCooperativeLevel,
7593 /*** Getters and setters **/
7594 IWineD3DDeviceImpl_SetClipPlane,
7595 IWineD3DDeviceImpl_GetClipPlane,
7596 IWineD3DDeviceImpl_SetClipStatus,
7597 IWineD3DDeviceImpl_GetClipStatus,
7598 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7599 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7600 IWineD3DDeviceImpl_SetDepthStencilSurface,
7601 IWineD3DDeviceImpl_GetDepthStencilSurface,
7602 IWineD3DDeviceImpl_SetFVF,
7603 IWineD3DDeviceImpl_GetFVF,
7604 IWineD3DDeviceImpl_SetGammaRamp,
7605 IWineD3DDeviceImpl_GetGammaRamp,
7606 IWineD3DDeviceImpl_SetIndices,
7607 IWineD3DDeviceImpl_GetIndices,
7608 IWineD3DDeviceImpl_SetBaseVertexIndex,
7609 IWineD3DDeviceImpl_GetBaseVertexIndex,
7610 IWineD3DDeviceImpl_SetLight,
7611 IWineD3DDeviceImpl_GetLight,
7612 IWineD3DDeviceImpl_SetLightEnable,
7613 IWineD3DDeviceImpl_GetLightEnable,
7614 IWineD3DDeviceImpl_SetMaterial,
7615 IWineD3DDeviceImpl_GetMaterial,
7616 IWineD3DDeviceImpl_SetNPatchMode,
7617 IWineD3DDeviceImpl_GetNPatchMode,
7618 IWineD3DDeviceImpl_SetPaletteEntries,
7619 IWineD3DDeviceImpl_GetPaletteEntries,
7620 IWineD3DDeviceImpl_SetPixelShader,
7621 IWineD3DDeviceImpl_GetPixelShader,
7622 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7623 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7624 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7625 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7626 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7627 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7628 IWineD3DDeviceImpl_SetRenderState,
7629 IWineD3DDeviceImpl_GetRenderState,
7630 IWineD3DDeviceImpl_SetRenderTarget,
7631 IWineD3DDeviceImpl_GetRenderTarget,
7632 IWineD3DDeviceImpl_SetFrontBackBuffers,
7633 IWineD3DDeviceImpl_SetSamplerState,
7634 IWineD3DDeviceImpl_GetSamplerState,
7635 IWineD3DDeviceImpl_SetScissorRect,
7636 IWineD3DDeviceImpl_GetScissorRect,
7637 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7638 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7639 IWineD3DDeviceImpl_SetStreamSource,
7640 IWineD3DDeviceImpl_GetStreamSource,
7641 IWineD3DDeviceImpl_SetStreamSourceFreq,
7642 IWineD3DDeviceImpl_GetStreamSourceFreq,
7643 IWineD3DDeviceImpl_SetTexture,
7644 IWineD3DDeviceImpl_GetTexture,
7645 IWineD3DDeviceImpl_SetTextureStageState,
7646 IWineD3DDeviceImpl_GetTextureStageState,
7647 IWineD3DDeviceImpl_SetTransform,
7648 IWineD3DDeviceImpl_GetTransform,
7649 IWineD3DDeviceImpl_SetVertexDeclaration,
7650 IWineD3DDeviceImpl_GetVertexDeclaration,
7651 IWineD3DDeviceImpl_SetVertexShader,
7652 IWineD3DDeviceImpl_GetVertexShader,
7653 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7654 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7655 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7656 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7657 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7658 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7659 IWineD3DDeviceImpl_SetViewport,
7660 IWineD3DDeviceImpl_GetViewport,
7661 IWineD3DDeviceImpl_MultiplyTransform,
7662 IWineD3DDeviceImpl_ValidateDevice,
7663 IWineD3DDeviceImpl_ProcessVertices,
7664 /*** State block ***/
7665 IWineD3DDeviceImpl_BeginStateBlock,
7666 IWineD3DDeviceImpl_EndStateBlock,
7667 /*** Scene management ***/
7668 IWineD3DDeviceImpl_BeginScene,
7669 IWineD3DDeviceImpl_EndScene,
7670 IWineD3DDeviceImpl_Present,
7671 IWineD3DDeviceImpl_Clear,
7673 IWineD3DDeviceImpl_DrawPrimitive,
7674 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7675 IWineD3DDeviceImpl_DrawPrimitiveUP,
7676 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7677 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7678 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7679 IWineD3DDeviceImpl_DrawRectPatch,
7680 IWineD3DDeviceImpl_DrawTriPatch,
7681 IWineD3DDeviceImpl_DeletePatch,
7682 IWineD3DDeviceImpl_ColorFill,
7683 IWineD3DDeviceImpl_UpdateTexture,
7684 IWineD3DDeviceImpl_UpdateSurface,
7685 IWineD3DDeviceImpl_GetFrontBufferData,
7686 /*** object tracking ***/
7687 IWineD3DDeviceImpl_ResourceReleased,
7688 IWineD3DDeviceImpl_EnumResources
7691 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7693 /*** IUnknown methods ***/
7694 IWineD3DDeviceImpl_QueryInterface,
7695 IWineD3DDeviceImpl_AddRef,
7696 IWineD3DDeviceImpl_Release,
7697 /*** IWineD3DDevice methods ***/
7698 IWineD3DDeviceImpl_GetParent,
7699 /*** Creation methods**/
7700 IWineD3DDeviceImpl_CreateVertexBuffer,
7701 IWineD3DDeviceImpl_CreateIndexBuffer,
7702 IWineD3DDeviceImpl_CreateStateBlock,
7703 IWineD3DDeviceImpl_CreateSurface,
7704 IWineD3DDeviceImpl_CreateTexture,
7705 IWineD3DDeviceImpl_CreateVolumeTexture,
7706 IWineD3DDeviceImpl_CreateVolume,
7707 IWineD3DDeviceImpl_CreateCubeTexture,
7708 IWineD3DDeviceImpl_CreateQuery,
7709 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7710 IWineD3DDeviceImpl_CreateVertexDeclaration,
7711 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7712 IWineD3DDeviceImpl_CreateVertexShader,
7713 IWineD3DDeviceImpl_CreatePixelShader,
7714 IWineD3DDeviceImpl_CreatePalette,
7715 /*** Odd functions **/
7716 IWineD3DDeviceImpl_Init3D,
7717 IWineD3DDeviceImpl_Uninit3D,
7718 IWineD3DDeviceImpl_SetFullscreen,
7719 IWineD3DDeviceImpl_SetMultithreaded,
7720 IWineD3DDeviceImpl_EvictManagedResources,
7721 IWineD3DDeviceImpl_GetAvailableTextureMem,
7722 IWineD3DDeviceImpl_GetBackBuffer,
7723 IWineD3DDeviceImpl_GetCreationParameters,
7724 IWineD3DDeviceImpl_GetDeviceCaps,
7725 IWineD3DDeviceImpl_GetDirect3D,
7726 IWineD3DDeviceImpl_GetDisplayMode,
7727 IWineD3DDeviceImpl_SetDisplayMode,
7728 IWineD3DDeviceImpl_GetHWND,
7729 IWineD3DDeviceImpl_SetHWND,
7730 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7731 IWineD3DDeviceImpl_GetRasterStatus,
7732 IWineD3DDeviceImpl_GetSwapChain,
7733 IWineD3DDeviceImpl_Reset,
7734 IWineD3DDeviceImpl_SetDialogBoxMode,
7735 IWineD3DDeviceImpl_SetCursorProperties,
7736 IWineD3DDeviceImpl_SetCursorPosition,
7737 IWineD3DDeviceImpl_ShowCursor,
7738 IWineD3DDeviceImpl_TestCooperativeLevel,
7739 /*** Getters and setters **/
7740 IWineD3DDeviceImpl_SetClipPlane,
7741 IWineD3DDeviceImpl_GetClipPlane,
7742 IWineD3DDeviceImpl_SetClipStatus,
7743 IWineD3DDeviceImpl_GetClipStatus,
7744 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7745 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7746 IWineD3DDeviceImpl_SetDepthStencilSurface,
7747 IWineD3DDeviceImpl_GetDepthStencilSurface,
7748 IWineD3DDeviceImpl_SetFVF,
7749 IWineD3DDeviceImpl_GetFVF,
7750 IWineD3DDeviceImpl_SetGammaRamp,
7751 IWineD3DDeviceImpl_GetGammaRamp,
7752 IWineD3DDeviceImpl_SetIndices,
7753 IWineD3DDeviceImpl_GetIndices,
7754 IWineD3DDeviceImpl_SetBaseVertexIndex,
7755 IWineD3DDeviceImpl_GetBaseVertexIndex,
7756 IWineD3DDeviceImpl_SetLight,
7757 IWineD3DDeviceImpl_GetLight,
7758 IWineD3DDeviceImpl_SetLightEnable,
7759 IWineD3DDeviceImpl_GetLightEnable,
7760 IWineD3DDeviceImpl_SetMaterial,
7761 IWineD3DDeviceImpl_GetMaterial,
7762 IWineD3DDeviceImpl_SetNPatchMode,
7763 IWineD3DDeviceImpl_GetNPatchMode,
7764 IWineD3DDeviceImpl_SetPaletteEntries,
7765 IWineD3DDeviceImpl_GetPaletteEntries,
7766 IWineD3DDeviceImpl_SetPixelShader,
7767 IWineD3DDeviceImpl_GetPixelShader,
7768 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7769 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7770 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7771 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7772 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7773 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7774 IWineD3DDeviceImpl_SetRenderState,
7775 IWineD3DDeviceImpl_GetRenderState,
7776 IWineD3DDeviceImpl_SetRenderTarget,
7777 IWineD3DDeviceImpl_GetRenderTarget,
7778 IWineD3DDeviceImpl_SetFrontBackBuffers,
7779 IWineD3DDeviceImpl_SetSamplerState,
7780 IWineD3DDeviceImpl_GetSamplerState,
7781 IWineD3DDeviceImpl_SetScissorRect,
7782 IWineD3DDeviceImpl_GetScissorRect,
7783 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7784 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7785 IWineD3DDeviceImpl_SetStreamSource,
7786 IWineD3DDeviceImpl_GetStreamSource,
7787 IWineD3DDeviceImpl_SetStreamSourceFreq,
7788 IWineD3DDeviceImpl_GetStreamSourceFreq,
7789 IWineD3DDeviceImpl_SetTexture,
7790 IWineD3DDeviceImpl_GetTexture,
7791 IWineD3DDeviceImpl_SetTextureStageState,
7792 IWineD3DDeviceImpl_GetTextureStageState,
7793 IWineD3DDeviceImpl_SetTransform,
7794 IWineD3DDeviceImpl_GetTransform,
7795 IWineD3DDeviceImpl_SetVertexDeclaration,
7796 IWineD3DDeviceImpl_GetVertexDeclaration,
7797 IWineD3DDeviceImpl_SetVertexShader,
7798 IWineD3DDeviceImpl_GetVertexShader,
7799 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7800 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7801 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7802 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7803 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7804 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7805 IWineD3DDeviceImpl_SetViewport,
7806 IWineD3DDeviceImpl_GetViewport,
7807 IWineD3DDeviceImpl_MultiplyTransform,
7808 IWineD3DDeviceImpl_ValidateDevice,
7809 IWineD3DDeviceImpl_ProcessVertices,
7810 /*** State block ***/
7811 IWineD3DDeviceImpl_BeginStateBlock,
7812 IWineD3DDeviceImpl_EndStateBlock,
7813 /*** Scene management ***/
7814 IWineD3DDeviceImpl_BeginScene,
7815 IWineD3DDeviceImpl_EndScene,
7816 IWineD3DDeviceImpl_Present,
7817 IWineD3DDeviceImpl_Clear,
7819 IWineD3DDeviceImpl_DrawPrimitive,
7820 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7821 IWineD3DDeviceImpl_DrawPrimitiveUP,
7822 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7823 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7824 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7825 IWineD3DDeviceImpl_DrawRectPatch,
7826 IWineD3DDeviceImpl_DrawTriPatch,
7827 IWineD3DDeviceImpl_DeletePatch,
7828 IWineD3DDeviceImpl_ColorFill,
7829 IWineD3DDeviceImpl_UpdateTexture,
7830 IWineD3DDeviceImpl_UpdateSurface,
7831 IWineD3DDeviceImpl_GetFrontBufferData,
7832 /*** object tracking ***/
7833 IWineD3DDeviceImpl_ResourceReleased,
7834 IWineD3DDeviceImpl_EnumResources
7837 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7838 WINED3DRS_ALPHABLENDENABLE ,
7839 WINED3DRS_ALPHAFUNC ,
7840 WINED3DRS_ALPHAREF ,
7841 WINED3DRS_ALPHATESTENABLE ,
7843 WINED3DRS_COLORWRITEENABLE ,
7844 WINED3DRS_DESTBLEND ,
7845 WINED3DRS_DITHERENABLE ,
7846 WINED3DRS_FILLMODE ,
7847 WINED3DRS_FOGDENSITY ,
7849 WINED3DRS_FOGSTART ,
7850 WINED3DRS_LASTPIXEL ,
7851 WINED3DRS_SHADEMODE ,
7852 WINED3DRS_SRCBLEND ,
7853 WINED3DRS_STENCILENABLE ,
7854 WINED3DRS_STENCILFAIL ,
7855 WINED3DRS_STENCILFUNC ,
7856 WINED3DRS_STENCILMASK ,
7857 WINED3DRS_STENCILPASS ,
7858 WINED3DRS_STENCILREF ,
7859 WINED3DRS_STENCILWRITEMASK ,
7860 WINED3DRS_STENCILZFAIL ,
7861 WINED3DRS_TEXTUREFACTOR ,
7872 WINED3DRS_ZWRITEENABLE
7875 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7876 WINED3DTSS_ADDRESSW ,
7877 WINED3DTSS_ALPHAARG0 ,
7878 WINED3DTSS_ALPHAARG1 ,
7879 WINED3DTSS_ALPHAARG2 ,
7880 WINED3DTSS_ALPHAOP ,
7881 WINED3DTSS_BUMPENVLOFFSET ,
7882 WINED3DTSS_BUMPENVLSCALE ,
7883 WINED3DTSS_BUMPENVMAT00 ,
7884 WINED3DTSS_BUMPENVMAT01 ,
7885 WINED3DTSS_BUMPENVMAT10 ,
7886 WINED3DTSS_BUMPENVMAT11 ,
7887 WINED3DTSS_COLORARG0 ,
7888 WINED3DTSS_COLORARG1 ,
7889 WINED3DTSS_COLORARG2 ,
7890 WINED3DTSS_COLOROP ,
7891 WINED3DTSS_RESULTARG ,
7892 WINED3DTSS_TEXCOORDINDEX ,
7893 WINED3DTSS_TEXTURETRANSFORMFLAGS
7896 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7897 WINED3DSAMP_ADDRESSU ,
7898 WINED3DSAMP_ADDRESSV ,
7899 WINED3DSAMP_ADDRESSW ,
7900 WINED3DSAMP_BORDERCOLOR ,
7901 WINED3DSAMP_MAGFILTER ,
7902 WINED3DSAMP_MINFILTER ,
7903 WINED3DSAMP_MIPFILTER ,
7904 WINED3DSAMP_MIPMAPLODBIAS ,
7905 WINED3DSAMP_MAXMIPLEVEL ,
7906 WINED3DSAMP_MAXANISOTROPY ,
7907 WINED3DSAMP_SRGBTEXTURE ,
7908 WINED3DSAMP_ELEMENTINDEX
7911 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7913 WINED3DRS_AMBIENTMATERIALSOURCE ,
7914 WINED3DRS_CLIPPING ,
7915 WINED3DRS_CLIPPLANEENABLE ,
7916 WINED3DRS_COLORVERTEX ,
7917 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7918 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7919 WINED3DRS_FOGDENSITY ,
7921 WINED3DRS_FOGSTART ,
7922 WINED3DRS_FOGTABLEMODE ,
7923 WINED3DRS_FOGVERTEXMODE ,
7924 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7925 WINED3DRS_LIGHTING ,
7926 WINED3DRS_LOCALVIEWER ,
7927 WINED3DRS_MULTISAMPLEANTIALIAS ,
7928 WINED3DRS_MULTISAMPLEMASK ,
7929 WINED3DRS_NORMALIZENORMALS ,
7930 WINED3DRS_PATCHEDGESTYLE ,
7931 WINED3DRS_POINTSCALE_A ,
7932 WINED3DRS_POINTSCALE_B ,
7933 WINED3DRS_POINTSCALE_C ,
7934 WINED3DRS_POINTSCALEENABLE ,
7935 WINED3DRS_POINTSIZE ,
7936 WINED3DRS_POINTSIZE_MAX ,
7937 WINED3DRS_POINTSIZE_MIN ,
7938 WINED3DRS_POINTSPRITEENABLE ,
7939 WINED3DRS_RANGEFOGENABLE ,
7940 WINED3DRS_SPECULARMATERIALSOURCE ,
7941 WINED3DRS_TWEENFACTOR ,
7942 WINED3DRS_VERTEXBLEND ,
7943 WINED3DRS_CULLMODE ,
7947 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7948 WINED3DTSS_TEXCOORDINDEX ,
7949 WINED3DTSS_TEXTURETRANSFORMFLAGS
7952 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7953 WINED3DSAMP_DMAPOFFSET
7956 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7957 DWORD rep = This->shader_backend->StateTable[state].representative;
7961 WineD3DContext *context;
7964 for(i = 0; i < This->numContexts; i++) {
7965 context = This->contexts[i];
7966 if(isStateDirty(context, rep)) continue;
7968 context->dirtyArray[context->numDirtyEntries++] = rep;
7971 context->isStateDirty[idx] |= (1 << shift);
7975 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7976 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7977 /* The drawable size of a pbuffer render target is the current pbuffer size
7979 *width = dev->pbufferWidth;
7980 *height = dev->pbufferHeight;
7983 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7984 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7986 *width = This->pow2Width;
7987 *height = This->pow2Height;
7990 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7991 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7992 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7993 * current context's drawable, which is the size of the back buffer of the swapchain
7994 * the active context belongs to. The back buffer of the swapchain is stored as the
7995 * surface the context belongs to.
7997 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7998 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;