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-2008 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 IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; ERR("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 object->resource.priority = 0; \
94 list_init(&object->resource.privateData); \
95 /* Check that we have enough video ram left */ \
96 if (Pool == WINED3DPOOL_DEFAULT) { \
97 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
98 WARN("Out of 'bogus' video memory\n"); \
99 HeapFree(GetProcessHeap(), 0, object); \
101 return WINED3DERR_OUTOFVIDEOMEMORY; \
103 WineD3DAdapterChangeGLRam(This, _size); \
105 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
106 if (object->resource.heapMemory == NULL && _size != 0) { \
107 FIXME("Out of memory!\n"); \
108 HeapFree(GetProcessHeap(), 0, object); \
110 return WINED3DERR_OUTOFVIDEOMEMORY; \
112 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
113 *pp##type = (IWineD3D##type *) object; \
114 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
115 TRACE("(%p) : Created resource %p\n", This, object); \
118 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
119 _basetexture.levels = Levels; \
120 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
121 _basetexture.LOD = 0; \
122 _basetexture.dirty = TRUE; \
123 _basetexture.is_srgb = FALSE; \
124 _basetexture.srgb_mode_change_count = 0; \
127 /**********************************************************
128 * Global variable / Constants follow
129 **********************************************************/
130 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
132 /**********************************************************
133 * IUnknown parts follows
134 **********************************************************/
136 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
140 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
141 if (IsEqualGUID(riid, &IID_IUnknown)
142 || IsEqualGUID(riid, &IID_IWineD3DBase)
143 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
144 IUnknown_AddRef(iface);
149 return E_NOINTERFACE;
152 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
153 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
154 ULONG refCount = InterlockedIncrement(&This->ref);
156 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
160 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
162 ULONG refCount = InterlockedDecrement(&This->ref);
164 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
167 /* TODO: Clean up all the surfaces and textures! */
168 /* NOTE: You must release the parent if the object was created via a callback
169 ** ***************************/
171 if (!list_empty(&This->resources)) {
172 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
173 dumpResources(&This->resources);
176 if(This->contexts) ERR("Context array not freed!\n");
177 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
178 This->haveHardwareCursor = FALSE;
180 IWineD3D_Release(This->wineD3D);
181 This->wineD3D = NULL;
182 HeapFree(GetProcessHeap(), 0, This);
183 TRACE("Freed device %p\n", This);
189 /**********************************************************
190 * IWineD3DDevice implementation follows
191 **********************************************************/
192 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
193 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
194 *pParent = This->parent;
195 IUnknown_AddRef(This->parent);
199 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
200 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 IWineD3DVertexBufferImpl *object;
204 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
205 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
209 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
210 *ppVertexBuffer = NULL;
211 return WINED3DERR_INVALIDCALL;
212 } else if(Pool == WINED3DPOOL_SCRATCH) {
213 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
214 * anyway, SCRATCH vertex buffers aren't usable anywhere
216 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
217 *ppVertexBuffer = NULL;
218 return WINED3DERR_INVALIDCALL;
221 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
223 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);
224 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
228 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
229 * drawStridedFast (half-life 2).
231 * Basically converting the vertices in the buffer is quite expensive, and observations
232 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
233 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
235 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
236 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
237 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
238 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
240 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
241 * more. In this call we can convert dx7 buffers too.
243 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
244 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
245 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
246 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
247 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
248 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
249 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
250 } else if(dxVersion <= 7 && conv) {
251 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
253 object->Flags |= VBFLAG_CREATEVBO;
258 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
259 GLenum error, glUsage;
260 TRACE("Creating VBO for Index Buffer %p\n", object);
262 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
263 * restored on the next draw
265 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
267 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
268 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
273 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
274 error = glGetError();
275 if(error != GL_NO_ERROR || object->vbo == 0) {
276 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
280 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
281 error = glGetError();
282 if(error != GL_NO_ERROR) {
283 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
287 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
288 * copy no readback will be needed
290 glUsage = GL_STATIC_DRAW_ARB;
291 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
292 error = glGetError();
293 if(error != GL_NO_ERROR) {
294 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
298 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
302 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
303 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
308 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
309 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
310 HANDLE *sharedHandle, IUnknown *parent) {
311 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
312 IWineD3DIndexBufferImpl *object;
313 TRACE("(%p) Creating index buffer\n", This);
315 /* Allocate the storage for the device */
316 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
318 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
319 CreateIndexBufferVBO(This, object);
322 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
323 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
324 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
329 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
332 IWineD3DStateBlockImpl *object;
336 D3DCREATEOBJECTINSTANCE(object, StateBlock)
337 object->blockType = Type;
339 for(i = 0; i < LIGHTMAP_SIZE; i++) {
340 list_init(&object->lightMap[i]);
343 temp_result = allocate_shader_constants(object);
344 if (FAILED(temp_result))
346 HeapFree(GetProcessHeap(), 0, object);
350 /* Special case - Used during initialization to produce a placeholder stateblock
351 so other functions called can update a state block */
352 if (Type == WINED3DSBT_INIT || Type == WINED3DSBT_RECORDED)
354 /* Don't bother increasing the reference count otherwise a device will never
355 be freed due to circular dependencies */
359 /* Otherwise, might as well set the whole state block to the appropriate values */
360 if (This->stateBlock != NULL)
361 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
363 memset(object->streamFreq, 1, sizeof(object->streamFreq));
365 /* Reset the ref and type after kludging it */
366 object->wineD3DDevice = This;
368 object->blockType = Type;
370 TRACE("Updating changed flags appropriate for type %d\n", Type);
372 if (Type == WINED3DSBT_ALL) {
374 TRACE("ALL => Pretend everything has changed\n");
375 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
377 /* Lights are not part of the changed / set structure */
378 for(j = 0; j < LIGHTMAP_SIZE; j++) {
380 LIST_FOR_EACH(e, &object->lightMap[j]) {
381 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
382 light->changed = TRUE;
383 light->enabledChanged = TRUE;
386 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
387 object->contained_render_states[j - 1] = j;
389 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
390 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
391 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
392 object->contained_transform_states[j - 1] = j;
394 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
395 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
396 object->contained_vs_consts_f[j] = j;
398 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
399 for(j = 0; j < MAX_CONST_I; j++) {
400 object->contained_vs_consts_i[j] = j;
402 object->num_contained_vs_consts_i = MAX_CONST_I;
403 for(j = 0; j < MAX_CONST_B; j++) {
404 object->contained_vs_consts_b[j] = j;
406 object->num_contained_vs_consts_b = MAX_CONST_B;
407 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
408 object->contained_ps_consts_f[j] = j;
410 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
411 for(j = 0; j < MAX_CONST_I; j++) {
412 object->contained_ps_consts_i[j] = j;
414 object->num_contained_ps_consts_i = MAX_CONST_I;
415 for(j = 0; j < MAX_CONST_B; j++) {
416 object->contained_ps_consts_b[j] = j;
418 object->num_contained_ps_consts_b = MAX_CONST_B;
419 for(i = 0; i < MAX_TEXTURES; i++) {
420 for (j = 0; j <= WINED3D_HIGHEST_TEXTURE_STATE; ++j)
422 object->contained_tss_states[object->num_contained_tss_states].stage = i;
423 object->contained_tss_states[object->num_contained_tss_states].state = j;
424 object->num_contained_tss_states++;
427 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
428 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
429 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
430 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
431 object->num_contained_sampler_states++;
435 for(i = 0; i < MAX_STREAMS; i++) {
436 if(object->streamSource[i]) {
437 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
440 if(object->pIndexData) {
441 IWineD3DIndexBuffer_AddRef(object->pIndexData);
443 if(object->vertexShader) {
444 IWineD3DVertexShader_AddRef(object->vertexShader);
446 if(object->pixelShader) {
447 IWineD3DPixelShader_AddRef(object->pixelShader);
450 } else if (Type == WINED3DSBT_PIXELSTATE) {
452 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
453 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
455 object->changed.pixelShader = TRUE;
457 /* Pixel Shader Constants */
458 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
459 object->contained_ps_consts_f[i] = i;
460 object->changed.pixelShaderConstantsF[i] = TRUE;
462 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
463 for (i = 0; i < MAX_CONST_B; ++i) {
464 object->contained_ps_consts_b[i] = i;
465 object->changed.pixelShaderConstantsB |= (1 << i);
467 object->num_contained_ps_consts_b = MAX_CONST_B;
468 for (i = 0; i < MAX_CONST_I; ++i) {
469 object->contained_ps_consts_i[i] = i;
470 object->changed.pixelShaderConstantsI |= (1 << i);
472 object->num_contained_ps_consts_i = MAX_CONST_I;
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
475 DWORD rs = SavedPixelStates_R[i];
476 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
477 object->contained_render_states[i] = rs;
479 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
480 for (j = 0; j < MAX_TEXTURES; j++) {
481 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
482 DWORD state = SavedPixelStates_T[i];
483 object->changed.textureState[j] |= 1 << state;
484 object->contained_tss_states[object->num_contained_tss_states].stage = j;
485 object->contained_tss_states[object->num_contained_tss_states].state = state;
486 object->num_contained_tss_states++;
489 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
490 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
491 DWORD state = SavedPixelStates_S[i];
492 object->changed.samplerState[j] |= 1 << state;
493 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
494 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
495 object->num_contained_sampler_states++;
498 if(object->pixelShader) {
499 IWineD3DPixelShader_AddRef(object->pixelShader);
502 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
503 * on them. This makes releasing the buffer easier
505 for(i = 0; i < MAX_STREAMS; i++) {
506 object->streamSource[i] = NULL;
508 object->pIndexData = NULL;
509 object->vertexShader = NULL;
511 } else if (Type == WINED3DSBT_VERTEXSTATE) {
513 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
514 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
516 object->changed.vertexShader = TRUE;
518 /* Vertex Shader Constants */
519 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
520 object->changed.vertexShaderConstantsF[i] = TRUE;
521 object->contained_vs_consts_f[i] = i;
523 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
524 for (i = 0; i < MAX_CONST_B; ++i) {
525 object->contained_vs_consts_b[i] = i;
526 object->changed.vertexShaderConstantsB |= (1 << i);
528 object->num_contained_vs_consts_b = MAX_CONST_B;
529 for (i = 0; i < MAX_CONST_I; ++i) {
530 object->contained_vs_consts_i[i] = i;
531 object->changed.vertexShaderConstantsI |= (1 << i);
533 object->num_contained_vs_consts_i = MAX_CONST_I;
534 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
535 DWORD rs = SavedVertexStates_R[i];
536 object->changed.renderState[rs >> 5] |= 1 << (rs & 0x1f);
537 object->contained_render_states[i] = rs;
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 DWORD state = SavedVertexStates_T[i];
543 object->changed.textureState[j] |= 1 << state;
544 object->contained_tss_states[object->num_contained_tss_states].stage = j;
545 object->contained_tss_states[object->num_contained_tss_states].state = state;
546 object->num_contained_tss_states++;
549 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
550 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
551 DWORD state = SavedVertexStates_S[i];
552 object->changed.samplerState[j] |= 1 << state;
553 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
554 object->contained_sampler_states[object->num_contained_sampler_states].state = state;
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 struct GlPixelFormatDesc *glDesc;
602 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
604 TRACE("(%p) Create surface\n",This);
606 /** FIXME: Check ranges on the inputs are valid
609 * [in] Quality level. The valid range is between zero and one less than the level
610 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
611 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
612 * values of paired render targets, depth stencil surfaces, and the MultiSample type
614 *******************************/
619 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
621 * If this flag is set, the contents of the depth stencil buffer will be
622 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
623 * with a different depth surface.
625 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
626 ***************************/
628 if(MultisampleQuality > 0) {
629 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
630 MultisampleQuality=0;
633 /** FIXME: Check that the format is supported
635 *******************************/
637 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
638 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
640 *********************************/
641 mul_4w = (Width + 3) & ~3;
642 mul_4h = (Height + 3) & ~3;
643 if (WINED3DFMT_UNKNOWN == Format) {
645 } else if (Format == WINED3DFMT_DXT1) {
646 /* DXT1 is half byte per pixel */
647 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
649 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
650 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
651 Format == WINED3DFMT_ATI2N) {
652 Size = (mul_4w * tableEntry->bpp * mul_4h);
654 /* The pitch is a multiple of 4 bytes */
655 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
659 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
661 /** Create and initialise the surface resource **/
662 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
663 /* "Standalone" surface */
664 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
666 object->currentDesc.Width = Width;
667 object->currentDesc.Height = Height;
668 object->currentDesc.MultiSampleType = MultiSample;
669 object->currentDesc.MultiSampleQuality = MultisampleQuality;
670 object->glDescription.level = Level;
671 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
672 list_init(&object->overlays);
675 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
676 object->Flags |= Discard ? SFLAG_DISCARD : 0;
677 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
678 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
681 if (WINED3DFMT_UNKNOWN != Format) {
682 object->bytesPerPixel = tableEntry->bpp;
684 object->bytesPerPixel = 0;
687 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
689 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
691 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
692 * this function is too deep to need to care about things like this.
693 * Levels need to be checked too, and possibly Type since they all affect what can be done.
694 * ****************************************/
696 case WINED3DPOOL_SCRATCH:
698 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
699 "which are mutually exclusive, setting lockable to TRUE\n");
702 case WINED3DPOOL_SYSTEMMEM:
703 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
704 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
705 case WINED3DPOOL_MANAGED:
706 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
707 "Usage of DYNAMIC which are mutually exclusive, not doing "
708 "anything just telling you.\n");
710 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
711 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
712 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
713 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
716 FIXME("(%p) Unknown pool %d\n", This, Pool);
720 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
721 FIXME("Trying to create a render target that isn't in the default pool\n");
724 /* mark the texture as dirty so that it gets loaded first time around*/
725 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
726 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
727 This, Width, Height, Format, debug_d3dformat(Format),
728 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
730 /* Look at the implementation and set the correct Vtable */
733 /* Check if a 3D adapter is available when creating gl surfaces */
735 ERR("OpenGL surfaces are not available without opengl\n");
736 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
737 HeapFree(GetProcessHeap(), 0, object);
738 return WINED3DERR_NOTAVAILABLE;
743 object->lpVtbl = &IWineGDISurface_Vtbl;
747 /* To be sure to catch this */
748 ERR("Unknown requested surface implementation %d!\n", Impl);
749 IWineD3DSurface_Release((IWineD3DSurface *) object);
750 return WINED3DERR_INVALIDCALL;
753 list_init(&object->renderbuffers);
755 /* Call the private setup routine */
756 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
760 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
761 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
762 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
763 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
765 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
766 IWineD3DTextureImpl *object;
771 unsigned int pow2Width;
772 unsigned int pow2Height;
773 const struct GlPixelFormatDesc *glDesc;
774 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
776 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
777 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
778 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
780 /* TODO: It should only be possible to create textures for formats
781 that are reported as supported */
782 if (WINED3DFMT_UNKNOWN >= Format) {
783 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
784 return WINED3DERR_INVALIDCALL;
787 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
788 D3DINITIALIZEBASETEXTURE(object->baseTexture);
789 object->width = Width;
790 object->height = Height;
792 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
793 object->baseTexture.minMipLookup = minMipLookup;
794 object->baseTexture.magLookup = magLookup;
796 object->baseTexture.minMipLookup = minMipLookup_noFilter;
797 object->baseTexture.magLookup = magLookup_noFilter;
800 /** Non-power2 support **/
801 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
805 /* Find the nearest pow2 match */
806 pow2Width = pow2Height = 1;
807 while (pow2Width < Width) pow2Width <<= 1;
808 while (pow2Height < Height) pow2Height <<= 1;
810 if(pow2Width != Width || pow2Height != Height) {
812 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
813 HeapFree(GetProcessHeap(), 0, object);
815 return WINED3DERR_INVALIDCALL;
822 /** FIXME: add support for real non-power-two if it's provided by the video card **/
823 /* Precalculated scaling for 'faked' non power of two texture coords.
824 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
825 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
826 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
828 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
829 object->baseTexture.pow2Matrix[0] = 1.0;
830 object->baseTexture.pow2Matrix[5] = 1.0;
831 object->baseTexture.pow2Matrix[10] = 1.0;
832 object->baseTexture.pow2Matrix[15] = 1.0;
833 object->target = GL_TEXTURE_2D;
834 object->cond_np2 = TRUE;
835 object->baseTexture.minMipLookup = minMipLookup_noFilter;
836 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
837 (Width != pow2Width || Height != pow2Height) &&
838 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
840 object->baseTexture.pow2Matrix[0] = (float)Width;
841 object->baseTexture.pow2Matrix[5] = (float)Height;
842 object->baseTexture.pow2Matrix[10] = 1.0;
843 object->baseTexture.pow2Matrix[15] = 1.0;
844 object->target = GL_TEXTURE_RECTANGLE_ARB;
845 object->cond_np2 = TRUE;
846 object->baseTexture.minMipLookup = minMipLookup_noFilter;
848 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
849 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
850 object->baseTexture.pow2Matrix[10] = 1.0;
851 object->baseTexture.pow2Matrix[15] = 1.0;
852 object->target = GL_TEXTURE_2D;
853 object->cond_np2 = FALSE;
855 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
857 /* Calculate levels for mip mapping */
858 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
859 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
860 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
861 return WINED3DERR_INVALIDCALL;
864 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
865 return WINED3DERR_INVALIDCALL;
867 object->baseTexture.levels = 1;
868 } else if (Levels == 0) {
869 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
870 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
873 /* Generate all the surfaces */
876 for (i = 0; i < object->baseTexture.levels; i++)
878 /* use the callback to create the texture surface */
879 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
880 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
881 FIXME("Failed to create surface %p\n", object);
883 object->surfaces[i] = NULL;
884 IWineD3DTexture_Release((IWineD3DTexture *)object);
890 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
891 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
892 surface_set_texture_target(object->surfaces[i], object->target);
893 /* calculate the next mipmap level */
894 tmpW = max(1, tmpW >> 1);
895 tmpH = max(1, tmpH >> 1);
897 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
899 TRACE("(%p) : Created texture %p\n", This, object);
903 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
904 UINT Width, UINT Height, UINT Depth,
905 UINT Levels, DWORD Usage,
906 WINED3DFORMAT Format, WINED3DPOOL Pool,
907 IWineD3DVolumeTexture **ppVolumeTexture,
908 HANDLE *pSharedHandle, IUnknown *parent,
909 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DVolumeTextureImpl *object;
917 const struct GlPixelFormatDesc *glDesc;
919 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN >= Format) {
924 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
925 return WINED3DERR_INVALIDCALL;
927 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
928 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
929 return WINED3DERR_INVALIDCALL;
932 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
933 D3DINITIALIZEBASETEXTURE(object->baseTexture);
935 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
936 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
938 /* Is NP2 support for volumes needed? */
939 object->baseTexture.pow2Matrix[ 0] = 1.0;
940 object->baseTexture.pow2Matrix[ 5] = 1.0;
941 object->baseTexture.pow2Matrix[10] = 1.0;
942 object->baseTexture.pow2Matrix[15] = 1.0;
944 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
945 object->baseTexture.minMipLookup = minMipLookup;
946 object->baseTexture.magLookup = magLookup;
948 object->baseTexture.minMipLookup = minMipLookup_noFilter;
949 object->baseTexture.magLookup = magLookup_noFilter;
952 /* Calculate levels for mip mapping */
953 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
954 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
955 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
956 return WINED3DERR_INVALIDCALL;
959 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
960 return WINED3DERR_INVALIDCALL;
962 object->baseTexture.levels = 1;
963 } else if (Levels == 0) {
964 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
965 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
968 /* Generate all the surfaces */
973 for (i = 0; i < object->baseTexture.levels; i++)
976 /* Create the volume */
977 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
978 &object->volumes[i], pSharedHandle);
981 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
982 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
983 *ppVolumeTexture = NULL;
987 /* Set its container to this object */
988 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
990 /* calculate the next mipmap level */
991 tmpW = max(1, tmpW >> 1);
992 tmpH = max(1, tmpH >> 1);
993 tmpD = max(1, tmpD >> 1);
995 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
997 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
998 TRACE("(%p) : Created volume texture %p\n", This, object);
1002 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1003 UINT Width, UINT Height, UINT Depth,
1005 WINED3DFORMAT Format, WINED3DPOOL Pool,
1006 IWineD3DVolume** ppVolume,
1007 HANDLE* pSharedHandle, IUnknown *parent) {
1009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1010 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1011 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1013 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1014 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1015 return WINED3DERR_INVALIDCALL;
1018 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1020 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1021 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1023 object->currentDesc.Width = Width;
1024 object->currentDesc.Height = Height;
1025 object->currentDesc.Depth = Depth;
1026 object->bytesPerPixel = formatDesc->bpp;
1028 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1029 object->lockable = TRUE;
1030 object->locked = FALSE;
1031 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1032 object->dirty = TRUE;
1034 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1037 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1038 UINT Levels, DWORD Usage,
1039 WINED3DFORMAT Format, WINED3DPOOL Pool,
1040 IWineD3DCubeTexture **ppCubeTexture,
1041 HANDLE *pSharedHandle, IUnknown *parent,
1042 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1045 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1049 unsigned int pow2EdgeLength;
1050 const struct GlPixelFormatDesc *glDesc;
1051 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1053 /* TODO: It should only be possible to create textures for formats
1054 that are reported as supported */
1055 if (WINED3DFMT_UNKNOWN >= Format) {
1056 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1057 return WINED3DERR_INVALIDCALL;
1060 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1061 WARN("(%p) : Tried to create not supported cube texture\n", This);
1062 return WINED3DERR_INVALIDCALL;
1065 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1066 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1068 TRACE("(%p) Create Cube Texture\n", This);
1070 /* Find the nearest pow2 match */
1072 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1074 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1075 /* Precalculated scaling for 'faked' non power of two texture coords */
1076 object->baseTexture.pow2Matrix[ 0] = 1.0;
1077 object->baseTexture.pow2Matrix[ 5] = 1.0;
1078 object->baseTexture.pow2Matrix[10] = 1.0;
1079 object->baseTexture.pow2Matrix[15] = 1.0;
1081 /* Precalculated scaling for 'faked' non power of two texture coords */
1082 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1083 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1084 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1085 object->baseTexture.pow2Matrix[15] = 1.0;
1088 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1089 object->baseTexture.minMipLookup = minMipLookup;
1090 object->baseTexture.magLookup = magLookup;
1092 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1093 object->baseTexture.magLookup = magLookup_noFilter;
1096 /* Calculate levels for mip mapping */
1097 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1098 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1099 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1100 HeapFree(GetProcessHeap(), 0, object);
1101 *ppCubeTexture = NULL;
1103 return WINED3DERR_INVALIDCALL;
1106 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1107 HeapFree(GetProcessHeap(), 0, object);
1108 *ppCubeTexture = NULL;
1110 return WINED3DERR_INVALIDCALL;
1112 object->baseTexture.levels = 1;
1113 } else if (Levels == 0) {
1114 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1115 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1118 /* Generate all the surfaces */
1120 for (i = 0; i < object->baseTexture.levels; i++) {
1122 /* Create the 6 faces */
1123 for (j = 0; j < 6; j++) {
1124 static const GLenum cube_targets[6] = {
1125 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1126 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1127 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1128 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1129 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1130 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1133 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1134 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1136 if(hr!= WINED3D_OK) {
1140 for (l = 0; l < j; l++) {
1141 IWineD3DSurface_Release(object->surfaces[l][i]);
1143 for (k = 0; k < i; k++) {
1144 for (l = 0; l < 6; l++) {
1145 IWineD3DSurface_Release(object->surfaces[l][k]);
1149 FIXME("(%p) Failed to create surface\n",object);
1150 HeapFree(GetProcessHeap(),0,object);
1151 *ppCubeTexture = NULL;
1154 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1155 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1156 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1158 tmpW = max(1, tmpW >> 1);
1160 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1162 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1163 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1167 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1169 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1170 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1171 const IWineD3DQueryVtbl *vtable;
1173 /* Just a check to see if we support this type of query */
1175 case WINED3DQUERYTYPE_OCCLUSION:
1176 TRACE("(%p) occlusion query\n", This);
1177 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1180 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1182 vtable = &IWineD3DOcclusionQuery_Vtbl;
1185 case WINED3DQUERYTYPE_EVENT:
1186 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1187 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1188 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1190 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1192 vtable = &IWineD3DEventQuery_Vtbl;
1196 case WINED3DQUERYTYPE_VCACHE:
1197 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1198 case WINED3DQUERYTYPE_VERTEXSTATS:
1199 case WINED3DQUERYTYPE_TIMESTAMP:
1200 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1201 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1202 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1203 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1204 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1205 case WINED3DQUERYTYPE_PIXELTIMINGS:
1206 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1207 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1209 /* Use the base Query vtable until we have a special one for each query */
1210 vtable = &IWineD3DQuery_Vtbl;
1211 FIXME("(%p) Unhandled query type %d\n", This, Type);
1213 if(NULL == ppQuery || hr != WINED3D_OK) {
1217 D3DCREATEOBJECTINSTANCE(object, Query)
1218 object->lpVtbl = vtable;
1219 object->type = Type;
1220 object->state = QUERY_CREATED;
1221 /* allocated the 'extended' data based on the type of query requested */
1223 case WINED3DQUERYTYPE_OCCLUSION:
1224 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1225 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1227 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1228 TRACE("(%p) Allocating data for an occlusion query\n", This);
1230 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1232 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1236 case WINED3DQUERYTYPE_EVENT:
1237 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1238 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1240 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1242 if(GL_SUPPORT(APPLE_FENCE)) {
1243 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1244 checkGLcall("glGenFencesAPPLE");
1245 } else if(GL_SUPPORT(NV_FENCE)) {
1246 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1247 checkGLcall("glGenFencesNV");
1252 case WINED3DQUERYTYPE_VCACHE:
1253 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1254 case WINED3DQUERYTYPE_VERTEXSTATS:
1255 case WINED3DQUERYTYPE_TIMESTAMP:
1256 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1257 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1258 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1259 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1260 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1261 case WINED3DQUERYTYPE_PIXELTIMINGS:
1262 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1263 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1265 object->extendedData = 0;
1266 FIXME("(%p) Unhandled query type %d\n",This , Type);
1268 TRACE("(%p) : Created Query %p\n", This, object);
1272 /*****************************************************************************
1273 * IWineD3DDeviceImpl_SetupFullscreenWindow
1275 * Helper function that modifies a HWND's Style and ExStyle for proper
1279 * iface: Pointer to the IWineD3DDevice interface
1280 * window: Window to setup
1282 *****************************************************************************/
1283 static LONG fullscreen_style(LONG orig_style) {
1284 LONG style = orig_style;
1285 style &= ~WS_CAPTION;
1286 style &= ~WS_THICKFRAME;
1288 /* Make sure the window is managed, otherwise we won't get keyboard input */
1289 style |= WS_POPUP | WS_SYSMENU;
1294 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1295 LONG exStyle = orig_exStyle;
1297 /* Filter out window decorations */
1298 exStyle &= ~WS_EX_WINDOWEDGE;
1299 exStyle &= ~WS_EX_CLIENTEDGE;
1304 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1307 LONG style, exStyle;
1308 /* Don't do anything if an original style is stored.
1309 * That shouldn't happen
1311 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1312 if (This->style || This->exStyle) {
1313 ERR("(%p): Want to change the window parameters of HWND %p, but "
1314 "another style is stored for restoration afterwards\n", This, window);
1317 /* Get the parameters and save them */
1318 style = GetWindowLongW(window, GWL_STYLE);
1319 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1320 This->style = style;
1321 This->exStyle = exStyle;
1323 style = fullscreen_style(style);
1324 exStyle = fullscreen_exStyle(exStyle);
1326 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1327 This->style, This->exStyle, style, exStyle);
1329 SetWindowLongW(window, GWL_STYLE, style);
1330 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1332 /* Inform the window about the update. */
1333 SetWindowPos(window, HWND_TOP, 0, 0,
1334 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1337 /*****************************************************************************
1338 * IWineD3DDeviceImpl_RestoreWindow
1340 * Helper function that restores a windows' properties when taking it out
1341 * of fullscreen mode
1344 * iface: Pointer to the IWineD3DDevice interface
1345 * window: Window to setup
1347 *****************************************************************************/
1348 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1349 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1350 LONG style, exStyle;
1352 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1353 * switch, do nothing
1355 if (!This->style && !This->exStyle) return;
1357 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1358 This, window, This->style, This->exStyle);
1360 style = GetWindowLongW(window, GWL_STYLE);
1361 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1363 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1364 * Some applications change it before calling Reset() when switching between windowed and
1365 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1367 if(style == fullscreen_style(This->style) &&
1368 exStyle == fullscreen_style(This->exStyle)) {
1369 SetWindowLongW(window, GWL_STYLE, This->style);
1370 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1373 /* Delete the old values */
1377 /* Inform the window about the update */
1378 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1379 0, 0, 0, 0, /* Pos, Size, ignored */
1380 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1383 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1384 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1385 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1386 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1387 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1392 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1394 IUnknown *bufferParent;
1395 BOOL displaymode_set = FALSE;
1396 WINED3DDISPLAYMODE Mode;
1397 const StaticPixelFormatDesc *formatDesc;
1399 TRACE("(%p) : Created Additional Swap Chain\n", This);
1401 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1402 * does a device hold a reference to a swap chain giving them a lifetime of the device
1403 * or does the swap chain notify the device of its destruction.
1404 *******************************/
1406 /* Check the params */
1407 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1408 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1409 return WINED3DERR_INVALIDCALL;
1410 } else if (pPresentationParameters->BackBufferCount > 1) {
1411 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");
1414 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1415 switch(surface_type) {
1417 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1419 case SURFACE_OPENGL:
1420 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1422 case SURFACE_UNKNOWN:
1423 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1424 return WINED3DERR_INVALIDCALL;
1427 /*********************
1428 * Lookup the window Handle and the relating X window handle
1429 ********************/
1431 /* Setup hwnd we are using, plus which display this equates to */
1432 object->win_handle = pPresentationParameters->hDeviceWindow;
1433 if (!object->win_handle) {
1434 object->win_handle = This->createParms.hFocusWindow;
1436 if(!pPresentationParameters->Windowed && object->win_handle) {
1437 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1438 pPresentationParameters->BackBufferWidth,
1439 pPresentationParameters->BackBufferHeight);
1442 hDc = GetDC(object->win_handle);
1443 TRACE("Using hDc %p\n", hDc);
1446 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1447 return WINED3DERR_NOTAVAILABLE;
1450 /* Get info on the current display setup */
1451 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1452 object->orig_width = Mode.Width;
1453 object->orig_height = Mode.Height;
1454 object->orig_fmt = Mode.Format;
1455 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1457 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1458 * then the corresponding dimension of the client area of the hDeviceWindow
1459 * (or the focus window, if hDeviceWindow is NULL) is taken.
1460 **********************/
1462 if (pPresentationParameters->Windowed &&
1463 ((pPresentationParameters->BackBufferWidth == 0) ||
1464 (pPresentationParameters->BackBufferHeight == 0) ||
1465 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1468 GetClientRect(object->win_handle, &Rect);
1470 if (pPresentationParameters->BackBufferWidth == 0) {
1471 pPresentationParameters->BackBufferWidth = Rect.right;
1472 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1474 if (pPresentationParameters->BackBufferHeight == 0) {
1475 pPresentationParameters->BackBufferHeight = Rect.bottom;
1476 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1478 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1479 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1480 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1484 /* Put the correct figures in the presentation parameters */
1485 TRACE("Copying across presentation parameters\n");
1486 object->presentParms = *pPresentationParameters;
1488 TRACE("calling rendertarget CB\n");
1489 hr = D3DCB_CreateRenderTarget(This->parent,
1491 object->presentParms.BackBufferWidth,
1492 object->presentParms.BackBufferHeight,
1493 object->presentParms.BackBufferFormat,
1494 object->presentParms.MultiSampleType,
1495 object->presentParms.MultiSampleQuality,
1496 TRUE /* Lockable */,
1497 &object->frontBuffer,
1498 NULL /* pShared (always null)*/);
1499 if (SUCCEEDED(hr)) {
1500 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1501 if(surface_type == SURFACE_OPENGL) {
1502 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1505 ERR("Failed to create the front buffer\n");
1509 /*********************
1510 * Windowed / Fullscreen
1511 *******************/
1514 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1515 * so we should really check to see if there is a fullscreen swapchain already
1516 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1517 **************************************/
1519 if (!pPresentationParameters->Windowed) {
1520 WINED3DDISPLAYMODE mode;
1523 /* Change the display settings */
1524 mode.Width = pPresentationParameters->BackBufferWidth;
1525 mode.Height = pPresentationParameters->BackBufferHeight;
1526 mode.Format = pPresentationParameters->BackBufferFormat;
1527 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1529 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1530 displaymode_set = TRUE;
1534 * Create an opengl context for the display visual
1535 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1536 * use different properties after that point in time. FIXME: How to handle when requested format
1537 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1538 * it chooses is identical to the one already being used!
1539 **********************************/
1540 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1542 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1543 if(!object->context) {
1544 ERR("Failed to create the context array\n");
1548 object->num_contexts = 1;
1550 if(surface_type == SURFACE_OPENGL) {
1551 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1552 if (!object->context[0]) {
1553 ERR("Failed to create a new context\n");
1554 hr = WINED3DERR_NOTAVAILABLE;
1557 TRACE("Context created (HWND=%p, glContext=%p)\n",
1558 object->win_handle, object->context[0]->glCtx);
1562 /*********************
1563 * Create the back, front and stencil buffers
1564 *******************/
1565 if(object->presentParms.BackBufferCount > 0) {
1568 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1569 if(!object->backBuffer) {
1570 ERR("Out of memory\n");
1575 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1576 TRACE("calling rendertarget CB\n");
1577 hr = D3DCB_CreateRenderTarget(This->parent,
1579 object->presentParms.BackBufferWidth,
1580 object->presentParms.BackBufferHeight,
1581 object->presentParms.BackBufferFormat,
1582 object->presentParms.MultiSampleType,
1583 object->presentParms.MultiSampleQuality,
1584 TRUE /* Lockable */,
1585 &object->backBuffer[i],
1586 NULL /* pShared (always null)*/);
1588 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1590 ERR("Cannot create new back buffer\n");
1593 if(surface_type == SURFACE_OPENGL) {
1595 glDrawBuffer(GL_BACK);
1596 checkGLcall("glDrawBuffer(GL_BACK)");
1601 object->backBuffer = NULL;
1603 /* Single buffering - draw to front buffer */
1604 if(surface_type == SURFACE_OPENGL) {
1606 glDrawBuffer(GL_FRONT);
1607 checkGLcall("glDrawBuffer(GL_FRONT)");
1612 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1613 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1614 TRACE("Creating depth stencil buffer\n");
1615 if (This->auto_depth_stencil_buffer == NULL ) {
1616 hr = D3DCB_CreateDepthStencil(This->parent,
1618 object->presentParms.BackBufferWidth,
1619 object->presentParms.BackBufferHeight,
1620 object->presentParms.AutoDepthStencilFormat,
1621 object->presentParms.MultiSampleType,
1622 object->presentParms.MultiSampleQuality,
1623 FALSE /* FIXME: Discard */,
1624 &This->auto_depth_stencil_buffer,
1625 NULL /* pShared (always null)*/ );
1626 if (SUCCEEDED(hr)) {
1627 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1629 ERR("Failed to create the auto depth stencil\n");
1635 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1637 TRACE("Created swapchain %p\n", object);
1638 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1642 if (displaymode_set) {
1646 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1649 /* Change the display settings */
1650 memset(&devmode, 0, sizeof(devmode));
1651 devmode.dmSize = sizeof(devmode);
1652 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1653 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1654 devmode.dmPelsWidth = object->orig_width;
1655 devmode.dmPelsHeight = object->orig_height;
1656 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1659 if (object->backBuffer) {
1661 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1662 if(object->backBuffer[i]) {
1663 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1664 IUnknown_Release(bufferParent); /* once for the get parent */
1665 if (IUnknown_Release(bufferParent) > 0) {
1666 FIXME("(%p) Something's still holding the back buffer\n",This);
1670 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1671 object->backBuffer = NULL;
1673 if(object->context && object->context[0])
1674 DestroyContext(This, object->context[0]);
1675 if(object->frontBuffer) {
1676 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1677 IUnknown_Release(bufferParent); /* once for the get parent */
1678 if (IUnknown_Release(bufferParent) > 0) {
1679 FIXME("(%p) Something's still holding the front buffer\n",This);
1682 HeapFree(GetProcessHeap(), 0, object);
1686 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1687 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1689 TRACE("(%p)\n", This);
1691 return This->NumberOfSwapChains;
1694 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1696 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1698 if(iSwapChain < This->NumberOfSwapChains) {
1699 *pSwapChain = This->swapchains[iSwapChain];
1700 IWineD3DSwapChain_AddRef(*pSwapChain);
1701 TRACE("(%p) returning %p\n", This, *pSwapChain);
1704 TRACE("Swapchain out of range\n");
1706 return WINED3DERR_INVALIDCALL;
1711 * Vertex Declaration
1713 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1714 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1716 IWineD3DVertexDeclarationImpl *object = NULL;
1717 HRESULT hr = WINED3D_OK;
1719 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1720 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1722 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1724 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1726 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1727 *ppVertexDeclaration = NULL;
1733 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1734 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1736 unsigned int idx, idx2;
1737 unsigned int offset;
1738 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1739 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1740 BOOL has_blend_idx = has_blend &&
1741 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1742 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1743 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1744 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1745 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1746 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1747 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1749 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1750 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1752 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1753 WINED3DVERTEXELEMENT *elements = NULL;
1756 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1757 if (has_blend_idx) num_blends--;
1759 /* Compute declaration size */
1760 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1761 has_psize + has_diffuse + has_specular + num_textures + 1;
1763 /* convert the declaration */
1764 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1768 elements[size-1] = end_element;
1771 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1772 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1773 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1775 else if ((fvf & WINED3DFVF_XYZW) == WINED3DFVF_XYZW) {
1776 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1777 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1780 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1781 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1783 elements[idx].UsageIndex = 0;
1786 if (has_blend && (num_blends > 0)) {
1787 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1788 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1790 switch(num_blends) {
1791 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1792 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1793 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1794 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1796 ERR("Unexpected amount of blend values: %u\n", num_blends);
1799 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1800 elements[idx].UsageIndex = 0;
1803 if (has_blend_idx) {
1804 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1805 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1806 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1807 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1808 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1810 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1811 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1812 elements[idx].UsageIndex = 0;
1816 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1817 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1818 elements[idx].UsageIndex = 0;
1822 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1823 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1824 elements[idx].UsageIndex = 0;
1828 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1829 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1830 elements[idx].UsageIndex = 0;
1834 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1835 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1836 elements[idx].UsageIndex = 1;
1839 for (idx2 = 0; idx2 < num_textures; idx2++) {
1840 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1841 switch (numcoords) {
1842 case WINED3DFVF_TEXTUREFORMAT1:
1843 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1845 case WINED3DFVF_TEXTUREFORMAT2:
1846 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1848 case WINED3DFVF_TEXTUREFORMAT3:
1849 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1851 case WINED3DFVF_TEXTUREFORMAT4:
1852 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1855 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1856 elements[idx].UsageIndex = idx2;
1860 /* Now compute offsets, and initialize the rest of the fields */
1861 for (idx = 0, offset = 0; idx < size-1; idx++) {
1862 elements[idx].Stream = 0;
1863 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1864 elements[idx].Offset = offset;
1865 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1868 *ppVertexElements = elements;
1872 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1873 WINED3DVERTEXELEMENT* elements = NULL;
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1878 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1879 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1881 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1882 HeapFree(GetProcessHeap(), 0, elements);
1883 if (hr != S_OK) return hr;
1888 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1889 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1890 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1891 HRESULT hr = WINED3D_OK;
1893 if (!pFunction) return WINED3DERR_INVALIDCALL;
1895 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1896 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1898 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1900 if (vertex_declaration) {
1901 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1904 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1906 if (WINED3D_OK != hr) {
1907 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1908 IWineD3DVertexShader_Release(*ppVertexShader);
1909 return WINED3DERR_INVALIDCALL;
1911 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1916 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1917 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1918 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1919 HRESULT hr = WINED3D_OK;
1921 if (!pFunction) return WINED3DERR_INVALIDCALL;
1923 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1924 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1925 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1926 if (WINED3D_OK == hr) {
1927 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1928 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1930 WARN("(%p) : Failed to create pixel shader\n", This);
1936 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1937 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1940 IWineD3DPaletteImpl *object;
1942 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1944 /* Create the new object */
1945 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1947 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1948 return E_OUTOFMEMORY;
1951 object->lpVtbl = &IWineD3DPalette_Vtbl;
1953 object->Flags = Flags;
1954 object->parent = Parent;
1955 object->wineD3DDevice = This;
1956 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1957 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1960 HeapFree( GetProcessHeap(), 0, object);
1961 return E_OUTOFMEMORY;
1964 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1966 IWineD3DPalette_Release((IWineD3DPalette *) object);
1970 *Palette = (IWineD3DPalette *) object;
1975 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1979 HDC dcb = NULL, dcs = NULL;
1980 WINEDDCOLORKEY colorkey;
1982 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1985 GetObjectA(hbm, sizeof(BITMAP), &bm);
1986 dcb = CreateCompatibleDC(NULL);
1988 SelectObject(dcb, hbm);
1992 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1993 * couldn't be loaded
1995 memset(&bm, 0, sizeof(bm));
2000 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
2001 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
2002 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
2004 ERR("Wine logo requested, but failed to create surface\n");
2009 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
2010 if(FAILED(hr)) goto out;
2011 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
2012 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2014 colorkey.dwColorSpaceLowValue = 0;
2015 colorkey.dwColorSpaceHighValue = 0;
2016 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2018 /* Fill the surface with a white color to show that wined3d is there */
2019 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2032 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2034 /* Under DirectX you can have texture stage operations even if no texture is
2035 bound, whereas opengl will only do texture operations when a valid texture is
2036 bound. We emulate this by creating dummy textures and binding them to each
2037 texture stage, but disable all stages by default. Hence if a stage is enabled
2038 then the default texture will kick in until replaced by a SetTexture call */
2041 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2042 /* The dummy texture does not have client storage backing */
2043 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2044 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2046 for (i = 0; i < GL_LIMITS(textures); i++) {
2047 GLubyte white = 255;
2049 /* Make appropriate texture active */
2050 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2051 checkGLcall("glActiveTextureARB");
2053 /* Generate an opengl texture name */
2054 glGenTextures(1, &This->dummyTextureName[i]);
2055 checkGLcall("glGenTextures");
2056 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2058 /* Generate a dummy 2d texture (not using 1d because they cause many
2059 * DRI drivers fall back to sw) */
2060 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2061 checkGLcall("glBindTexture");
2063 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2064 checkGLcall("glTexImage2D");
2066 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2067 /* Reenable because if supported it is enabled by default */
2068 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2069 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2075 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2077 IWineD3DSwapChainImpl *swapchain = NULL;
2082 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2083 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2084 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2086 /* TODO: Test if OpenGL is compiled in and loaded */
2088 TRACE("(%p) : Creating stateblock\n", This);
2089 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2090 hr = IWineD3DDevice_CreateStateBlock(iface,
2092 (IWineD3DStateBlock **)&This->stateBlock,
2094 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2095 WARN("Failed to create stateblock\n");
2098 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2099 This->updateStateBlock = This->stateBlock;
2100 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2102 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2103 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2105 This->NumberOfPalettes = 1;
2106 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2107 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2108 ERR("Out of memory!\n");
2111 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2112 if(!This->palettes[0]) {
2113 ERR("Out of memory!\n");
2116 for (i = 0; i < 256; ++i) {
2117 This->palettes[0][i].peRed = 0xFF;
2118 This->palettes[0][i].peGreen = 0xFF;
2119 This->palettes[0][i].peBlue = 0xFF;
2120 This->palettes[0][i].peFlags = 0xFF;
2122 This->currentPalette = 0;
2124 /* Initialize the texture unit mapping to a 1:1 mapping */
2125 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2126 if (state < GL_LIMITS(fragment_samplers)) {
2127 This->texUnitMap[state] = state;
2128 This->rev_tex_unit_map[state] = state;
2130 This->texUnitMap[state] = -1;
2131 This->rev_tex_unit_map[state] = -1;
2135 /* Setup the implicit swapchain */
2136 TRACE("Creating implicit swapchain\n");
2137 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2138 if (FAILED(hr) || !swapchain) {
2139 WARN("Failed to create implicit swapchain\n");
2143 This->NumberOfSwapChains = 1;
2144 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2145 if(!This->swapchains) {
2146 ERR("Out of memory!\n");
2149 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2151 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2152 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2153 This->render_targets[0] = swapchain->backBuffer[0];
2154 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2157 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2158 This->render_targets[0] = swapchain->frontBuffer;
2159 This->lastActiveRenderTarget = swapchain->frontBuffer;
2161 IWineD3DSurface_AddRef(This->render_targets[0]);
2162 This->activeContext = swapchain->context[0];
2163 This->lastThread = GetCurrentThreadId();
2165 /* Depth Stencil support */
2166 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2167 if (NULL != This->stencilBufferTarget) {
2168 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2171 hr = This->shader_backend->shader_alloc_private(iface);
2173 TRACE("Shader private data couldn't be allocated\n");
2176 hr = This->frag_pipe->alloc_private(iface);
2178 TRACE("Fragment pipeline private data couldn't be allocated\n");
2181 hr = This->blitter->alloc_private(iface);
2183 TRACE("Blitter private data couldn't be allocated\n");
2187 /* Set up some starting GL setup */
2189 /* Setup all the devices defaults */
2190 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2191 create_dummy_textures(This);
2195 /* Initialize the current view state */
2196 This->view_ident = 1;
2197 This->contexts[0]->last_was_rhw = 0;
2198 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2199 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2201 switch(wined3d_settings.offscreen_rendering_mode) {
2204 This->offscreenBuffer = GL_BACK;
2207 case ORM_BACKBUFFER:
2209 if(This->activeContext->aux_buffers > 0) {
2210 TRACE("Using auxilliary buffer for offscreen rendering\n");
2211 This->offscreenBuffer = GL_AUX0;
2213 TRACE("Using back buffer for offscreen rendering\n");
2214 This->offscreenBuffer = GL_BACK;
2219 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2222 /* Clear the screen */
2223 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2224 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2227 This->d3d_initialized = TRUE;
2229 if(wined3d_settings.logo) {
2230 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2232 This->highest_dirty_ps_const = 0;
2233 This->highest_dirty_vs_const = 0;
2237 HeapFree(GetProcessHeap(), 0, This->render_targets);
2238 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2239 HeapFree(GetProcessHeap(), 0, This->swapchains);
2240 This->NumberOfSwapChains = 0;
2241 if(This->palettes) {
2242 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2243 HeapFree(GetProcessHeap(), 0, This->palettes);
2245 This->NumberOfPalettes = 0;
2247 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2249 if(This->stateBlock) {
2250 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2251 This->stateBlock = NULL;
2253 if (This->blit_priv) {
2254 This->blitter->free_private(iface);
2256 if (This->fragment_priv) {
2257 This->frag_pipe->free_private(iface);
2259 if (This->shader_priv) {
2260 This->shader_backend->shader_free_private(iface);
2265 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2266 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2267 IWineD3DSwapChainImpl *swapchain = NULL;
2270 /* Setup the implicit swapchain */
2271 TRACE("Creating implicit swapchain\n");
2272 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2273 if (FAILED(hr) || !swapchain) {
2274 WARN("Failed to create implicit swapchain\n");
2278 This->NumberOfSwapChains = 1;
2279 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2280 if(!This->swapchains) {
2281 ERR("Out of memory!\n");
2284 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2288 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2292 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2293 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2296 TRACE("(%p)\n", This);
2298 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2300 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2301 * it was created. Thus make sure a context is active for the glDelete* calls
2303 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2305 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2307 TRACE("Deleting high order patches\n");
2308 for(i = 0; i < PATCHMAP_SIZE; i++) {
2309 struct list *e1, *e2;
2310 struct WineD3DRectPatch *patch;
2311 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2312 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2313 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2317 /* Delete the palette conversion shader if it is around */
2318 if(This->paletteConversionShader) {
2320 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2322 This->paletteConversionShader = 0;
2325 /* Delete the pbuffer context if there is any */
2326 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2328 /* Delete the mouse cursor texture */
2329 if(This->cursorTexture) {
2331 glDeleteTextures(1, &This->cursorTexture);
2333 This->cursorTexture = 0;
2336 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2337 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2339 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2340 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2343 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2344 * private data, it might contain opengl pointers
2346 if(This->depth_blt_texture) {
2347 glDeleteTextures(1, &This->depth_blt_texture);
2348 This->depth_blt_texture = 0;
2350 if (This->depth_blt_rb) {
2351 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2352 This->depth_blt_rb = 0;
2353 This->depth_blt_rb_w = 0;
2354 This->depth_blt_rb_h = 0;
2357 /* Release the update stateblock */
2358 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2359 if(This->updateStateBlock != This->stateBlock)
2360 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2362 This->updateStateBlock = NULL;
2364 { /* because were not doing proper internal refcounts releasing the primary state block
2365 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2366 to set this->stateBlock = NULL; first */
2367 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2368 This->stateBlock = NULL;
2370 /* Release the stateblock */
2371 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2372 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2376 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2377 This->blitter->free_private(iface);
2378 This->frag_pipe->free_private(iface);
2379 This->shader_backend->shader_free_private(iface);
2381 /* Release the buffers (with sanity checks)*/
2382 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2383 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2384 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2385 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2387 This->stencilBufferTarget = NULL;
2389 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2390 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2391 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2393 TRACE("Setting rendertarget to NULL\n");
2394 This->render_targets[0] = NULL;
2396 if (This->auto_depth_stencil_buffer) {
2397 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2398 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2400 This->auto_depth_stencil_buffer = NULL;
2403 for(i=0; i < This->NumberOfSwapChains; i++) {
2404 TRACE("Releasing the implicit swapchain %d\n", i);
2405 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2406 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2410 HeapFree(GetProcessHeap(), 0, This->swapchains);
2411 This->swapchains = NULL;
2412 This->NumberOfSwapChains = 0;
2414 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2415 HeapFree(GetProcessHeap(), 0, This->palettes);
2416 This->palettes = NULL;
2417 This->NumberOfPalettes = 0;
2419 HeapFree(GetProcessHeap(), 0, This->render_targets);
2420 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2421 This->render_targets = NULL;
2422 This->draw_buffers = NULL;
2424 This->d3d_initialized = FALSE;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2432 for(i=0; i < This->NumberOfSwapChains; i++) {
2433 TRACE("Releasing the implicit swapchain %d\n", i);
2434 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2435 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2439 HeapFree(GetProcessHeap(), 0, This->swapchains);
2440 This->swapchains = NULL;
2441 This->NumberOfSwapChains = 0;
2445 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2446 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2447 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2449 * There is no way to deactivate thread safety once it is enabled.
2451 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2454 /*For now just store the flag(needed in case of ddraw) */
2455 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2460 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2461 const WINED3DDISPLAYMODE* pMode) {
2463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2465 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2468 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2470 /* Resize the screen even without a window:
2471 * The app could have unset it with SetCooperativeLevel, but not called
2472 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2473 * but we don't have any hwnd
2476 memset(&devmode, 0, sizeof(devmode));
2477 devmode.dmSize = sizeof(devmode);
2478 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2479 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2480 devmode.dmPelsWidth = pMode->Width;
2481 devmode.dmPelsHeight = pMode->Height;
2483 devmode.dmDisplayFrequency = pMode->RefreshRate;
2484 if (pMode->RefreshRate != 0) {
2485 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2488 /* Only change the mode if necessary */
2489 if( (This->ddraw_width == pMode->Width) &&
2490 (This->ddraw_height == pMode->Height) &&
2491 (This->ddraw_format == pMode->Format) &&
2492 (pMode->RefreshRate == 0) ) {
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2497 if (ret != DISP_CHANGE_SUCCESSFUL) {
2498 if(devmode.dmDisplayFrequency != 0) {
2499 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2500 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2501 devmode.dmDisplayFrequency = 0;
2502 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2504 if(ret != DISP_CHANGE_SUCCESSFUL) {
2505 return WINED3DERR_NOTAVAILABLE;
2509 /* Store the new values */
2510 This->ddraw_width = pMode->Width;
2511 This->ddraw_height = pMode->Height;
2512 This->ddraw_format = pMode->Format;
2514 /* And finally clip mouse to our screen */
2515 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2516 ClipCursor(&clip_rc);
2521 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2522 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2523 *ppD3D= This->wineD3D;
2524 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2525 IWineD3D_AddRef(*ppD3D);
2529 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2533 (This->adapter->TextureRam/(1024*1024)),
2534 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2535 /* return simulated texture memory left */
2536 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2540 * Get / Set Stream Source
2542 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2544 IWineD3DVertexBuffer *oldSrc;
2546 if (StreamNumber >= MAX_STREAMS) {
2547 WARN("Stream out of range %d\n", StreamNumber);
2548 return WINED3DERR_INVALIDCALL;
2549 } else if(OffsetInBytes & 0x3) {
2550 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2551 return WINED3DERR_INVALIDCALL;
2554 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2555 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2557 This->updateStateBlock->changed.streamSource |= 1 << StreamNumber;
2559 if(oldSrc == pStreamData &&
2560 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2561 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2562 TRACE("Application is setting the old values over, nothing to do\n");
2566 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2568 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2569 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2572 /* Handle recording of state blocks */
2573 if (This->isRecordingState) {
2574 TRACE("Recording... not performing anything\n");
2575 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2576 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2580 /* Need to do a getParent and pass the references up */
2581 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2582 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2583 so for now, just count internally */
2584 if (pStreamData != NULL) {
2585 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2586 InterlockedIncrement(&vbImpl->bindCount);
2587 IWineD3DVertexBuffer_AddRef(pStreamData);
2589 if (oldSrc != NULL) {
2590 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2591 IWineD3DVertexBuffer_Release(oldSrc);
2594 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2599 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2602 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2603 This->stateBlock->streamSource[StreamNumber],
2604 This->stateBlock->streamOffset[StreamNumber],
2605 This->stateBlock->streamStride[StreamNumber]);
2607 if (StreamNumber >= MAX_STREAMS) {
2608 WARN("Stream out of range %d\n", StreamNumber);
2609 return WINED3DERR_INVALIDCALL;
2611 *pStream = This->stateBlock->streamSource[StreamNumber];
2612 *pStride = This->stateBlock->streamStride[StreamNumber];
2614 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2617 if (*pStream != NULL) {
2618 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2623 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2625 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2626 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2628 /* Verify input at least in d3d9 this is invalid*/
2629 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2630 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2631 return WINED3DERR_INVALIDCALL;
2633 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2634 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2635 return WINED3DERR_INVALIDCALL;
2638 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2639 return WINED3DERR_INVALIDCALL;
2642 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2643 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2645 This->updateStateBlock->changed.streamFreq |= 1 << StreamNumber;
2646 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2648 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2649 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2650 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2656 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2660 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2662 TRACE("(%p) : returning %d\n", This, *Divider);
2668 * Get / Set & Multiply Transform
2670 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2673 /* Most of this routine, comments included copied from ddraw tree initially: */
2674 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2676 /* Handle recording of state blocks */
2677 if (This->isRecordingState) {
2678 TRACE("Recording... not performing anything\n");
2679 This->updateStateBlock->changed.transform[d3dts >> 5] |= 1 << (d3dts & 0x1f);
2680 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2685 * If the new matrix is the same as the current one,
2686 * we cut off any further processing. this seems to be a reasonable
2687 * optimization because as was noticed, some apps (warcraft3 for example)
2688 * tend towards setting the same matrix repeatedly for some reason.
2690 * From here on we assume that the new matrix is different, wherever it matters.
2692 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2693 TRACE("The app is setting the same matrix over again\n");
2696 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2700 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2701 where ViewMat = Camera space, WorldMat = world space.
2703 In OpenGL, camera and world space is combined into GL_MODELVIEW
2704 matrix. The Projection matrix stay projection matrix.
2707 /* Capture the times we can just ignore the change for now */
2708 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2709 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2710 /* Handled by the state manager */
2713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2717 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2719 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2720 *pMatrix = This->stateBlock->transforms[State];
2724 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2725 const WINED3DMATRIX *mat = NULL;
2728 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2729 * below means it will be recorded in a state block change, but it
2730 * works regardless where it is recorded.
2731 * If this is found to be wrong, change to StateBlock.
2733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2734 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2736 if (State <= HIGHEST_TRANSFORMSTATE)
2738 mat = &This->updateStateBlock->transforms[State];
2740 FIXME("Unhandled transform state!!\n");
2743 multiply_matrix(&temp, mat, pMatrix);
2745 /* Apply change via set transform - will reapply to eg. lights this way */
2746 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2752 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2753 you can reference any indexes you want as long as that number max are enabled at any
2754 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2755 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2756 but when recording, just build a chain pretty much of commands to be replayed. */
2758 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2760 PLIGHTINFOEL *object = NULL;
2761 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2767 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2771 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2772 return WINED3DERR_INVALIDCALL;
2775 switch(pLight->Type) {
2776 case WINED3DLIGHT_POINT:
2777 case WINED3DLIGHT_SPOT:
2778 case WINED3DLIGHT_PARALLELPOINT:
2779 case WINED3DLIGHT_GLSPOT:
2780 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2783 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2784 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2785 return WINED3DERR_INVALIDCALL;
2789 case WINED3DLIGHT_DIRECTIONAL:
2790 /* Ignores attenuation */
2794 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2795 return WINED3DERR_INVALIDCALL;
2798 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2799 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2800 if(object->OriginalIndex == Index) break;
2805 TRACE("Adding new light\n");
2806 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2808 ERR("Out of memory error when allocating a light\n");
2809 return E_OUTOFMEMORY;
2811 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2812 object->glIndex = -1;
2813 object->OriginalIndex = Index;
2814 object->changed = TRUE;
2817 /* Initialize the object */
2818 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,
2819 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2820 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2821 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2822 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2823 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2824 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2826 /* Save away the information */
2827 object->OriginalParms = *pLight;
2829 switch (pLight->Type) {
2830 case WINED3DLIGHT_POINT:
2832 object->lightPosn[0] = pLight->Position.x;
2833 object->lightPosn[1] = pLight->Position.y;
2834 object->lightPosn[2] = pLight->Position.z;
2835 object->lightPosn[3] = 1.0f;
2836 object->cutoff = 180.0f;
2840 case WINED3DLIGHT_DIRECTIONAL:
2842 object->lightPosn[0] = -pLight->Direction.x;
2843 object->lightPosn[1] = -pLight->Direction.y;
2844 object->lightPosn[2] = -pLight->Direction.z;
2845 object->lightPosn[3] = 0.0;
2846 object->exponent = 0.0f;
2847 object->cutoff = 180.0f;
2850 case WINED3DLIGHT_SPOT:
2852 object->lightPosn[0] = pLight->Position.x;
2853 object->lightPosn[1] = pLight->Position.y;
2854 object->lightPosn[2] = pLight->Position.z;
2855 object->lightPosn[3] = 1.0;
2858 object->lightDirn[0] = pLight->Direction.x;
2859 object->lightDirn[1] = pLight->Direction.y;
2860 object->lightDirn[2] = pLight->Direction.z;
2861 object->lightDirn[3] = 1.0;
2864 * opengl-ish and d3d-ish spot lights use too different models for the
2865 * light "intensity" as a function of the angle towards the main light direction,
2866 * so we only can approximate very roughly.
2867 * however spot lights are rather rarely used in games (if ever used at all).
2868 * furthermore if still used, probably nobody pays attention to such details.
2870 if (pLight->Falloff == 0) {
2871 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2872 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2873 * will always be 1.0 for both of them, and we don't have to care for the
2874 * rest of the rather complex calculation
2876 object->exponent = 0;
2878 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2879 if (rho < 0.0001) rho = 0.0001f;
2880 object->exponent = -0.3/log(cos(rho/2));
2882 if (object->exponent > 128.0) {
2883 object->exponent = 128.0;
2885 object->cutoff = pLight->Phi*90/M_PI;
2891 FIXME("Unrecognized light type %d\n", pLight->Type);
2894 /* Update the live definitions if the light is currently assigned a glIndex */
2895 if (object->glIndex != -1 && !This->isRecordingState) {
2896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2901 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2902 PLIGHTINFOEL *lightInfo = NULL;
2903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2904 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2906 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2908 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2909 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2910 if(lightInfo->OriginalIndex == Index) break;
2914 if (lightInfo == NULL) {
2915 TRACE("Light information requested but light not defined\n");
2916 return WINED3DERR_INVALIDCALL;
2919 *pLight = lightInfo->OriginalParms;
2924 * Get / Set Light Enable
2925 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2927 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2928 PLIGHTINFOEL *lightInfo = NULL;
2929 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2930 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2932 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2934 /* Tests show true = 128...not clear why */
2935 Enable = Enable? 128: 0;
2937 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2938 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2939 if(lightInfo->OriginalIndex == Index) break;
2942 TRACE("Found light: %p\n", lightInfo);
2944 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2945 if (lightInfo == NULL) {
2947 TRACE("Light enabled requested but light not defined, so defining one!\n");
2948 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2950 /* Search for it again! Should be fairly quick as near head of list */
2951 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2952 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2953 if(lightInfo->OriginalIndex == Index) break;
2956 if (lightInfo == NULL) {
2957 FIXME("Adding default lights has failed dismally\n");
2958 return WINED3DERR_INVALIDCALL;
2962 lightInfo->enabledChanged = TRUE;
2964 if(lightInfo->glIndex != -1) {
2965 if(!This->isRecordingState) {
2966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2969 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
2970 lightInfo->glIndex = -1;
2972 TRACE("Light already disabled, nothing to do\n");
2974 lightInfo->enabled = FALSE;
2976 lightInfo->enabled = TRUE;
2977 if (lightInfo->glIndex != -1) {
2979 TRACE("Nothing to do as light was enabled\n");
2982 /* Find a free gl light */
2983 for(i = 0; i < This->maxConcurrentLights; i++) {
2984 if(This->updateStateBlock->activeLights[i] == NULL) {
2985 This->updateStateBlock->activeLights[i] = lightInfo;
2986 lightInfo->glIndex = i;
2990 if(lightInfo->glIndex == -1) {
2991 /* Our tests show that Windows returns D3D_OK in this situation, even with
2992 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2993 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2994 * as well for those lights.
2996 * TODO: Test how this affects rendering
2998 WARN("Too many concurrently active lights\n");
3002 /* i == lightInfo->glIndex */
3003 if(!This->isRecordingState) {
3004 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3012 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3014 PLIGHTINFOEL *lightInfo = NULL;
3015 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3017 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3018 TRACE("(%p) : for idx(%d)\n", This, Index);
3020 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3021 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3022 if(lightInfo->OriginalIndex == Index) break;
3026 if (lightInfo == NULL) {
3027 TRACE("Light enabled state requested but light not defined\n");
3028 return WINED3DERR_INVALIDCALL;
3030 /* true is 128 according to SetLightEnable */
3031 *pEnable = lightInfo->enabled ? 128 : 0;
3036 * Get / Set Clip Planes
3038 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3042 /* Validate Index */
3043 if (Index >= GL_LIMITS(clipplanes)) {
3044 TRACE("Application has requested clipplane this device doesn't support\n");
3045 return WINED3DERR_INVALIDCALL;
3048 This->updateStateBlock->changed.clipplane |= 1 << Index;
3050 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3051 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3052 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3053 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3054 TRACE("Application is setting old values over, nothing to do\n");
3058 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3059 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3060 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3061 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3063 /* Handle recording of state blocks */
3064 if (This->isRecordingState) {
3065 TRACE("Recording... not performing anything\n");
3069 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3074 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 TRACE("(%p) : for idx %d\n", This, Index);
3078 /* Validate Index */
3079 if (Index >= GL_LIMITS(clipplanes)) {
3080 TRACE("Application has requested clipplane this device doesn't support\n");
3081 return WINED3DERR_INVALIDCALL;
3084 pPlane[0] = This->stateBlock->clipplane[Index][0];
3085 pPlane[1] = This->stateBlock->clipplane[Index][1];
3086 pPlane[2] = This->stateBlock->clipplane[Index][2];
3087 pPlane[3] = This->stateBlock->clipplane[Index][3];
3092 * Get / Set Clip Plane Status
3093 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3095 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3096 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3097 FIXME("(%p) : stub\n", This);
3098 if (NULL == pClipStatus) {
3099 return WINED3DERR_INVALIDCALL;
3101 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3102 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3106 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 FIXME("(%p) : stub\n", This);
3109 if (NULL == pClipStatus) {
3110 return WINED3DERR_INVALIDCALL;
3112 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3113 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3118 * Get / Set Material
3120 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3121 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3123 This->updateStateBlock->changed.material = TRUE;
3124 This->updateStateBlock->material = *pMaterial;
3126 /* Handle recording of state blocks */
3127 if (This->isRecordingState) {
3128 TRACE("Recording... not performing anything\n");
3132 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3136 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3138 *pMaterial = This->updateStateBlock->material;
3139 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3140 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3141 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3142 pMaterial->Ambient.b, pMaterial->Ambient.a);
3143 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3144 pMaterial->Specular.b, pMaterial->Specular.a);
3145 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3146 pMaterial->Emissive.b, pMaterial->Emissive.a);
3147 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3155 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3156 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 IWineD3DIndexBuffer *oldIdxs;
3159 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3160 oldIdxs = This->updateStateBlock->pIndexData;
3162 This->updateStateBlock->changed.indices = TRUE;
3163 This->updateStateBlock->pIndexData = pIndexData;
3165 /* Handle recording of state blocks */
3166 if (This->isRecordingState) {
3167 TRACE("Recording... not performing anything\n");
3168 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3169 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3173 if(oldIdxs != pIndexData) {
3174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3175 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3176 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3181 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3182 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 *ppIndexData = This->stateBlock->pIndexData;
3186 /* up ref count on ppindexdata */
3188 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3189 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3191 TRACE("(%p) No index data set\n", This);
3193 TRACE("Returning %p\n", *ppIndexData);
3198 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3199 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3201 TRACE("(%p)->(%d)\n", This, BaseIndex);
3203 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3204 TRACE("Application is setting the old value over, nothing to do\n");
3208 This->updateStateBlock->baseVertexIndex = BaseIndex;
3210 if (This->isRecordingState) {
3211 TRACE("Recording... not performing anything\n");
3214 /* The base vertex index affects the stream sources */
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3219 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3220 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3221 TRACE("(%p) : base_index %p\n", This, base_index);
3223 *base_index = This->stateBlock->baseVertexIndex;
3225 TRACE("Returning %u\n", *base_index);
3231 * Get / Set Viewports
3233 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3236 TRACE("(%p)\n", This);
3237 This->updateStateBlock->changed.viewport = TRUE;
3238 This->updateStateBlock->viewport = *pViewport;
3240 /* Handle recording of state blocks */
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3246 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3247 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3249 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3254 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3255 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3256 TRACE("(%p)\n", This);
3257 *pViewport = This->stateBlock->viewport;
3262 * Get / Set Render States
3263 * TODO: Verify against dx9 definitions
3265 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3268 DWORD oldValue = This->stateBlock->renderState[State];
3270 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3272 This->updateStateBlock->changed.renderState[State >> 5] |= 1 << (State & 0x1f);
3273 This->updateStateBlock->renderState[State] = Value;
3275 /* Handle recording of state blocks */
3276 if (This->isRecordingState) {
3277 TRACE("Recording... not performing anything\n");
3281 /* Compared here and not before the assignment to allow proper stateblock recording */
3282 if(Value == oldValue) {
3283 TRACE("Application is setting the old value over, nothing to do\n");
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3291 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3293 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3294 *pValue = This->stateBlock->renderState[State];
3299 * Get / Set Sampler States
3300 * TODO: Verify against dx9 definitions
3303 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3304 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3307 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3308 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3310 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3311 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3314 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3315 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3316 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3319 * SetSampler is designed to allow for more than the standard up to 8 textures
3320 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3321 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3323 * http://developer.nvidia.com/object/General_FAQ.html#t6
3325 * There are two new settings for GForce
3327 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3328 * and the texture one:
3329 * GL_MAX_TEXTURE_COORDS_ARB.
3330 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3333 oldValue = This->stateBlock->samplerState[Sampler][Type];
3334 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3335 This->updateStateBlock->changed.samplerState[Sampler] |= 1 << Type;
3337 /* Handle recording of state blocks */
3338 if (This->isRecordingState) {
3339 TRACE("Recording... not performing anything\n");
3343 if(oldValue == Value) {
3344 TRACE("Application is setting the old value over, nothing to do\n");
3348 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3353 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3354 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3356 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3357 This, Sampler, debug_d3dsamplerstate(Type), Type);
3359 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3360 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3363 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3364 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3365 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3367 *Value = This->stateBlock->samplerState[Sampler][Type];
3368 TRACE("(%p) : Returning %#x\n", This, *Value);
3373 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3376 This->updateStateBlock->changed.scissorRect = TRUE;
3377 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3378 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3381 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3383 if(This->isRecordingState) {
3384 TRACE("Recording... not performing anything\n");
3388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3393 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3396 *pRect = This->updateStateBlock->scissorRect;
3397 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3401 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3403 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3405 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3407 This->updateStateBlock->vertexDecl = pDecl;
3408 This->updateStateBlock->changed.vertexDecl = TRUE;
3410 if (This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3413 } else if(pDecl == oldDecl) {
3414 /* Checked after the assignment to allow proper stateblock recording */
3415 TRACE("Application is setting the old declaration over, nothing to do\n");
3419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3423 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3426 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3428 *ppDecl = This->stateBlock->vertexDecl;
3429 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3433 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3435 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3437 This->updateStateBlock->vertexShader = pShader;
3438 This->updateStateBlock->changed.vertexShader = TRUE;
3440 if (This->isRecordingState) {
3441 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3442 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3443 TRACE("Recording... not performing anything\n");
3445 } else if(oldShader == pShader) {
3446 /* Checked here to allow proper stateblock recording */
3447 TRACE("App is setting the old shader over, nothing to do\n");
3451 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3452 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3453 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3460 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3463 if (NULL == ppShader) {
3464 return WINED3DERR_INVALIDCALL;
3466 *ppShader = This->stateBlock->vertexShader;
3467 if( NULL != *ppShader)
3468 IWineD3DVertexShader_AddRef(*ppShader);
3470 TRACE("(%p) : returning %p\n", This, *ppShader);
3474 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3475 IWineD3DDevice *iface,
3477 CONST BOOL *srcData,
3480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3481 int i, cnt = min(count, MAX_CONST_B - start);
3483 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3484 iface, srcData, start, count);
3486 if (srcData == NULL || cnt < 0)
3487 return WINED3DERR_INVALIDCALL;
3489 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3490 for (i = 0; i < cnt; i++)
3491 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3493 for (i = start; i < cnt + start; ++i) {
3494 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3497 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3502 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3503 IWineD3DDevice *iface,
3508 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3509 int cnt = min(count, MAX_CONST_B - start);
3511 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3512 iface, dstData, start, count);
3514 if (dstData == NULL || cnt < 0)
3515 return WINED3DERR_INVALIDCALL;
3517 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3521 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3522 IWineD3DDevice *iface,
3527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3528 int i, cnt = min(count, MAX_CONST_I - start);
3530 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3531 iface, srcData, start, count);
3533 if (srcData == NULL || cnt < 0)
3534 return WINED3DERR_INVALIDCALL;
3536 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3537 for (i = 0; i < cnt; i++)
3538 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3539 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3541 for (i = start; i < cnt + start; ++i) {
3542 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3545 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3550 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3551 IWineD3DDevice *iface,
3556 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3557 int cnt = min(count, MAX_CONST_I - start);
3559 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3560 iface, dstData, start, count);
3562 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3563 return WINED3DERR_INVALIDCALL;
3565 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3569 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3570 IWineD3DDevice *iface,
3572 CONST float *srcData,
3575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3578 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3579 iface, srcData, start, count);
3581 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3582 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3583 return WINED3DERR_INVALIDCALL;
3585 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3587 for (i = 0; i < count; i++)
3588 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3589 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3592 if (!This->isRecordingState)
3594 This->shader_backend->shader_update_float_vertex_constants(iface, start, count);
3595 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3598 memset(This->updateStateBlock->changed.vertexShaderConstantsF + start, 1,
3599 sizeof(*This->updateStateBlock->changed.vertexShaderConstantsF) * count);
3604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3605 IWineD3DDevice *iface,
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3613 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3614 iface, dstData, start, count);
3616 if (dstData == NULL || cnt < 0)
3617 return WINED3DERR_INVALIDCALL;
3619 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3623 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3625 for(i = 0; i <= WINED3D_HIGHEST_TEXTURE_STATE; ++i)
3627 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3631 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3632 int i = This->rev_tex_unit_map[unit];
3633 int j = This->texUnitMap[stage];
3635 This->texUnitMap[stage] = unit;
3636 if (i != -1 && i != stage) {
3637 This->texUnitMap[i] = -1;
3640 This->rev_tex_unit_map[unit] = stage;
3641 if (j != -1 && j != unit) {
3642 This->rev_tex_unit_map[j] = -1;
3646 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3649 This->fixed_function_usage_map = 0;
3650 for (i = 0; i < MAX_TEXTURES; ++i) {
3651 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3652 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3653 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3654 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3655 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3656 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3657 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3658 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3660 if (color_op == WINED3DTOP_DISABLE) {
3661 /* Not used, and disable higher stages */
3665 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3666 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3667 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3668 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3669 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3670 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3671 This->fixed_function_usage_map |= (1 << i);
3674 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3675 This->fixed_function_usage_map |= (1 << (i + 1));
3680 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3684 device_update_fixed_function_usage_map(This);
3685 ffu_map = This->fixed_function_usage_map;
3687 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3688 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3689 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3691 if (!(ffu_map & 1)) continue;
3693 if (This->texUnitMap[i] != i) {
3694 device_map_stage(This, i, i);
3695 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3696 markTextureStagesDirty(This, i);
3702 /* Now work out the mapping */
3704 for (i = 0; ffu_map; ffu_map >>= 1, ++i)
3706 if (!(ffu_map & 1)) continue;
3708 if (This->texUnitMap[i] != tex) {
3709 device_map_stage(This, i, tex);
3710 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3711 markTextureStagesDirty(This, i);
3718 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3719 const DWORD *sampler_tokens =
3720 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3723 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3724 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3725 device_map_stage(This, i, i);
3726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3727 if (i < MAX_TEXTURES) {
3728 markTextureStagesDirty(This, i);
3734 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3735 const DWORD *vshader_sampler_tokens, int unit)
3737 int current_mapping = This->rev_tex_unit_map[unit];
3739 if (current_mapping == -1) {
3740 /* Not currently used */
3744 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3745 /* Used by a fragment sampler */
3747 if (!pshader_sampler_tokens) {
3748 /* No pixel shader, check fixed function */
3749 return current_mapping >= MAX_TEXTURES || !(This->fixed_function_usage_map & (1 << current_mapping));
3752 /* Pixel shader, check the shader's sampler map */
3753 return !pshader_sampler_tokens[current_mapping];
3756 /* Used by a vertex sampler */
3757 return !vshader_sampler_tokens[current_mapping];
3760 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3761 const DWORD *vshader_sampler_tokens =
3762 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3763 const DWORD *pshader_sampler_tokens = NULL;
3764 int start = GL_LIMITS(combined_samplers) - 1;
3768 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3770 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3771 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3772 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3775 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3776 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3777 if (vshader_sampler_tokens[i]) {
3778 if (This->texUnitMap[vsampler_idx] != -1) {
3779 /* Already mapped somewhere */
3783 while (start >= 0) {
3784 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3785 device_map_stage(This, vsampler_idx, start);
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3798 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3799 BOOL vs = use_vs(This->stateBlock);
3800 BOOL ps = use_ps(This->stateBlock);
3803 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3804 * that would be really messy and require shader recompilation
3805 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3806 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3809 device_map_psamplers(This);
3811 device_map_fixed_function_samplers(This);
3815 device_map_vsamplers(This, ps);
3819 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3820 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3821 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3822 This->updateStateBlock->pixelShader = pShader;
3823 This->updateStateBlock->changed.pixelShader = TRUE;
3825 /* Handle recording of state blocks */
3826 if (This->isRecordingState) {
3827 TRACE("Recording... not performing anything\n");
3830 if (This->isRecordingState) {
3831 TRACE("Recording... not performing anything\n");
3832 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3833 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3837 if(pShader == oldShader) {
3838 TRACE("App is setting the old pixel shader over, nothing to do\n");
3842 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3843 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3845 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3851 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3854 if (NULL == ppShader) {
3855 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3856 return WINED3DERR_INVALIDCALL;
3859 *ppShader = This->stateBlock->pixelShader;
3860 if (NULL != *ppShader) {
3861 IWineD3DPixelShader_AddRef(*ppShader);
3863 TRACE("(%p) : returning %p\n", This, *ppShader);
3867 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3868 IWineD3DDevice *iface,
3870 CONST BOOL *srcData,
3873 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3874 int i, cnt = min(count, MAX_CONST_B - start);
3876 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3877 iface, srcData, start, count);
3879 if (srcData == NULL || cnt < 0)
3880 return WINED3DERR_INVALIDCALL;
3882 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3883 for (i = 0; i < cnt; i++)
3884 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3886 for (i = start; i < cnt + start; ++i) {
3887 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3890 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3895 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3896 IWineD3DDevice *iface,
3901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3902 int cnt = min(count, MAX_CONST_B - start);
3904 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3905 iface, dstData, start, count);
3907 if (dstData == NULL || cnt < 0)
3908 return WINED3DERR_INVALIDCALL;
3910 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3914 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3915 IWineD3DDevice *iface,
3920 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3921 int i, cnt = min(count, MAX_CONST_I - start);
3923 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3924 iface, srcData, start, count);
3926 if (srcData == NULL || cnt < 0)
3927 return WINED3DERR_INVALIDCALL;
3929 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3930 for (i = 0; i < cnt; i++)
3931 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3932 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3934 for (i = start; i < cnt + start; ++i) {
3935 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
3938 if (!This->isRecordingState) IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3943 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3944 IWineD3DDevice *iface,
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 int cnt = min(count, MAX_CONST_I - start);
3952 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3953 iface, dstData, start, count);
3955 if (dstData == NULL || cnt < 0)
3956 return WINED3DERR_INVALIDCALL;
3958 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3962 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3963 IWineD3DDevice *iface,
3965 CONST float *srcData,
3968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3971 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3972 iface, srcData, start, count);
3974 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3975 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3976 return WINED3DERR_INVALIDCALL;
3978 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3980 for (i = 0; i < count; i++)
3981 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3982 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3985 if (!This->isRecordingState)
3987 This->shader_backend->shader_update_float_pixel_constants(iface, start, count);
3988 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3991 memset(This->updateStateBlock->changed.pixelShaderConstantsF + start, 1,
3992 sizeof(*This->updateStateBlock->changed.pixelShaderConstantsF) * count);
3997 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
3998 IWineD3DDevice *iface,
4003 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4004 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4006 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4007 iface, dstData, start, count);
4009 if (dstData == NULL || cnt < 0)
4010 return WINED3DERR_INVALIDCALL;
4012 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4016 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4017 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4018 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4020 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4022 DWORD DestFVF = dest->fvf;
4024 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4028 if (lpStrideData->u.s.normal.lpData) {
4029 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4032 if (lpStrideData->u.s.position.lpData == NULL) {
4033 ERR("Source has no position mask\n");
4034 return WINED3DERR_INVALIDCALL;
4037 /* We might access VBOs from this code, so hold the lock */
4040 if (dest->resource.allocatedMemory == NULL) {
4041 /* This may happen if we do direct locking into a vbo. Unlikely,
4042 * but theoretically possible(ddraw processvertices test)
4044 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4045 if(!dest->resource.allocatedMemory) {
4047 ERR("Out of memory\n");
4048 return E_OUTOFMEMORY;
4052 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4053 checkGLcall("glBindBufferARB");
4054 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4056 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4058 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4059 checkGLcall("glUnmapBufferARB");
4063 /* Get a pointer into the destination vbo(create one if none exists) and
4064 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4066 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4067 dest->Flags |= VBFLAG_CREATEVBO;
4068 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4072 unsigned char extrabytes = 0;
4073 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4074 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4075 * this may write 4 extra bytes beyond the area that should be written
4077 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4078 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4079 if(!dest_conv_addr) {
4080 ERR("Out of memory\n");
4081 /* Continue without storing converted vertices */
4083 dest_conv = dest_conv_addr;
4087 * a) WINED3DRS_CLIPPING is enabled
4088 * b) WINED3DVOP_CLIP is passed
4090 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4091 static BOOL warned = FALSE;
4093 * The clipping code is not quite correct. Some things need
4094 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4095 * so disable clipping for now.
4096 * (The graphics in Half-Life are broken, and my processvertices
4097 * test crashes with IDirect3DDevice3)
4103 FIXME("Clipping is broken and disabled for now\n");
4105 } else doClip = FALSE;
4106 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4108 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4111 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4112 WINED3DTS_PROJECTION,
4114 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4115 WINED3DTS_WORLDMATRIX(0),
4118 TRACE("View mat:\n");
4119 TRACE("%f %f %f %f\n", view_mat.u.s._11, view_mat.u.s._12, view_mat.u.s._13, view_mat.u.s._14);
4120 TRACE("%f %f %f %f\n", view_mat.u.s._21, view_mat.u.s._22, view_mat.u.s._23, view_mat.u.s._24);
4121 TRACE("%f %f %f %f\n", view_mat.u.s._31, view_mat.u.s._32, view_mat.u.s._33, view_mat.u.s._34);
4122 TRACE("%f %f %f %f\n", view_mat.u.s._41, view_mat.u.s._42, view_mat.u.s._43, view_mat.u.s._44);
4124 TRACE("Proj mat:\n");
4125 TRACE("%f %f %f %f\n", proj_mat.u.s._11, proj_mat.u.s._12, proj_mat.u.s._13, proj_mat.u.s._14);
4126 TRACE("%f %f %f %f\n", proj_mat.u.s._21, proj_mat.u.s._22, proj_mat.u.s._23, proj_mat.u.s._24);
4127 TRACE("%f %f %f %f\n", proj_mat.u.s._31, proj_mat.u.s._32, proj_mat.u.s._33, proj_mat.u.s._34);
4128 TRACE("%f %f %f %f\n", proj_mat.u.s._41, proj_mat.u.s._42, proj_mat.u.s._43, proj_mat.u.s._44);
4130 TRACE("World mat:\n");
4131 TRACE("%f %f %f %f\n", world_mat.u.s._11, world_mat.u.s._12, world_mat.u.s._13, world_mat.u.s._14);
4132 TRACE("%f %f %f %f\n", world_mat.u.s._21, world_mat.u.s._22, world_mat.u.s._23, world_mat.u.s._24);
4133 TRACE("%f %f %f %f\n", world_mat.u.s._31, world_mat.u.s._32, world_mat.u.s._33, world_mat.u.s._34);
4134 TRACE("%f %f %f %f\n", world_mat.u.s._41, world_mat.u.s._42, world_mat.u.s._43, world_mat.u.s._44);
4136 /* Get the viewport */
4137 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4138 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4139 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4141 multiply_matrix(&mat,&view_mat,&world_mat);
4142 multiply_matrix(&mat,&proj_mat,&mat);
4144 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4146 for (i = 0; i < dwCount; i+= 1) {
4147 unsigned int tex_index;
4149 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4150 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4151 /* The position first */
4153 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4155 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4157 /* Multiplication with world, view and projection matrix */
4158 x = (p[0] * mat.u.s._11) + (p[1] * mat.u.s._21) + (p[2] * mat.u.s._31) + (1.0 * mat.u.s._41);
4159 y = (p[0] * mat.u.s._12) + (p[1] * mat.u.s._22) + (p[2] * mat.u.s._32) + (1.0 * mat.u.s._42);
4160 z = (p[0] * mat.u.s._13) + (p[1] * mat.u.s._23) + (p[2] * mat.u.s._33) + (1.0 * mat.u.s._43);
4161 rhw = (p[0] * mat.u.s._14) + (p[1] * mat.u.s._24) + (p[2] * mat.u.s._34) + (1.0 * mat.u.s._44);
4163 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4165 /* WARNING: The following things are taken from d3d7 and were not yet checked
4166 * against d3d8 or d3d9!
4169 /* Clipping conditions: From msdn
4171 * A vertex is clipped if it does not match the following requirements
4175 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4177 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4178 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4183 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4184 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4187 /* "Normal" viewport transformation (not clipped)
4188 * 1) The values are divided by rhw
4189 * 2) The y axis is negative, so multiply it with -1
4190 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4191 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4192 * 4) Multiply x with Width/2 and add Width/2
4193 * 5) The same for the height
4194 * 6) Add the viewpoint X and Y to the 2D coordinates and
4195 * The minimum Z value to z
4196 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4198 * Well, basically it's simply a linear transformation into viewport
4210 z *= vp.MaxZ - vp.MinZ;
4212 x += vp.Width / 2 + vp.X;
4213 y += vp.Height / 2 + vp.Y;
4218 /* That vertex got clipped
4219 * Contrary to OpenGL it is not dropped completely, it just
4220 * undergoes a different calculation.
4222 TRACE("Vertex got clipped\n");
4229 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4230 * outside of the main vertex buffer memory. That needs some more
4235 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4238 ( (float *) dest_ptr)[0] = x;
4239 ( (float *) dest_ptr)[1] = y;
4240 ( (float *) dest_ptr)[2] = z;
4241 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4243 dest_ptr += 3 * sizeof(float);
4245 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4246 dest_ptr += sizeof(float);
4251 ( (float *) dest_conv)[0] = x * w;
4252 ( (float *) dest_conv)[1] = y * w;
4253 ( (float *) dest_conv)[2] = z * w;
4254 ( (float *) dest_conv)[3] = w;
4256 dest_conv += 3 * sizeof(float);
4258 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4259 dest_conv += sizeof(float);
4263 if (DestFVF & WINED3DFVF_PSIZE) {
4264 dest_ptr += sizeof(DWORD);
4265 if(dest_conv) dest_conv += sizeof(DWORD);
4267 if (DestFVF & WINED3DFVF_NORMAL) {
4268 const float *normal =
4269 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4270 /* AFAIK this should go into the lighting information */
4271 FIXME("Didn't expect the destination to have a normal\n");
4272 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4274 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4278 if (DestFVF & WINED3DFVF_DIFFUSE) {
4279 const DWORD *color_d =
4280 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4282 static BOOL warned = FALSE;
4285 ERR("No diffuse color in source, but destination has one\n");
4289 *( (DWORD *) dest_ptr) = 0xffffffff;
4290 dest_ptr += sizeof(DWORD);
4293 *( (DWORD *) dest_conv) = 0xffffffff;
4294 dest_conv += sizeof(DWORD);
4298 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4300 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4301 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4302 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4303 dest_conv += sizeof(DWORD);
4308 if (DestFVF & WINED3DFVF_SPECULAR) {
4309 /* What's the color value in the feedback buffer? */
4310 const DWORD *color_s =
4311 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4313 static BOOL warned = FALSE;
4316 ERR("No specular color in source, but destination has one\n");
4320 *( (DWORD *) dest_ptr) = 0xFF000000;
4321 dest_ptr += sizeof(DWORD);
4324 *( (DWORD *) dest_conv) = 0xFF000000;
4325 dest_conv += sizeof(DWORD);
4329 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4331 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4332 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4333 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4334 dest_conv += sizeof(DWORD);
4339 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4340 const float *tex_coord =
4341 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4342 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4344 ERR("No source texture, but destination requests one\n");
4345 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4346 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4349 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4351 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4358 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4359 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4360 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4361 dwCount * get_flexible_vertex_size(DestFVF),
4363 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4364 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4371 #undef copy_and_next
4373 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4374 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4375 WineDirect3DVertexStridedData strided;
4376 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4377 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4380 ERR("Output vertex declaration not implemented yet\n");
4383 /* Need any context to write to the vbo. */
4384 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4386 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4387 * control the streamIsUP flag, thus restore it afterwards.
4389 This->stateBlock->streamIsUP = FALSE;
4390 memset(&strided, 0, sizeof(strided));
4391 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4392 This->stateBlock->streamIsUP = streamWasUP;
4394 if(vbo || SrcStartIndex) {
4396 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4397 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4399 * Also get the start index in, but only loop over all elements if there's something to add at all.
4401 #define FIXSRC(type) \
4402 if(strided.u.s.type.VBO) { \
4403 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4404 strided.u.s.type.VBO = 0; \
4405 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4407 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4411 if(strided.u.s.type.lpData) { \
4412 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4415 FIXSRC(blendWeights);
4416 FIXSRC(blendMatrixIndices);
4421 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4422 FIXSRC(texCoords[i]);
4435 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4439 * Get / Set Texture Stage States
4440 * TODO: Verify against dx9 definitions
4442 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4444 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4446 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4448 if (Stage >= MAX_TEXTURES) {
4449 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4453 This->updateStateBlock->changed.textureState[Stage] |= 1 << Type;
4454 This->updateStateBlock->textureState[Stage][Type] = Value;
4456 if (This->isRecordingState) {
4457 TRACE("Recording... not performing anything\n");
4461 /* Checked after the assignments to allow proper stateblock recording */
4462 if(oldValue == Value) {
4463 TRACE("App is setting the old value over, nothing to do\n");
4467 if(Stage > This->stateBlock->lowest_disabled_stage &&
4468 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4469 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4470 * Changes in other states are important on disabled stages too
4475 if(Type == WINED3DTSS_COLOROP) {
4478 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4479 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4480 * they have to be disabled
4482 * The current stage is dirtified below.
4484 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4485 TRACE("Additionally dirtifying stage %d\n", i);
4486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4488 This->stateBlock->lowest_disabled_stage = Stage;
4489 TRACE("New lowest disabled: %d\n", Stage);
4490 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4491 /* Previously disabled stage enabled. Stages above it may need enabling
4492 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4493 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4495 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4498 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4499 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4502 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4503 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4505 This->stateBlock->lowest_disabled_stage = i;
4506 TRACE("New lowest disabled: %d\n", i);
4510 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4515 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4517 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4518 *pValue = This->updateStateBlock->textureState[Stage][Type];
4525 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4527 IWineD3DBaseTexture *oldTexture;
4529 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4531 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4532 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4535 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4536 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4537 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4540 oldTexture = This->updateStateBlock->textures[Stage];
4542 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4543 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4545 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4546 return WINED3DERR_INVALIDCALL;
4549 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4550 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4552 This->updateStateBlock->changed.textures |= 1 << Stage;
4553 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4554 This->updateStateBlock->textures[Stage] = pTexture;
4556 /* Handle recording of state blocks */
4557 if (This->isRecordingState) {
4558 TRACE("Recording... not performing anything\n");
4562 if(oldTexture == pTexture) {
4563 TRACE("App is setting the same texture again, nothing to do\n");
4567 /** NOTE: MSDN says that setTexture increases the reference count,
4568 * and that the application must set the texture back to null (or have a leaky application),
4569 * This means we should pass the refcount up to the parent
4570 *******************************/
4571 if (NULL != This->updateStateBlock->textures[Stage]) {
4572 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4573 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4575 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4576 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4577 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4578 * so the COLOROP and ALPHAOP have to be dirtified.
4580 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4583 if(bindCount == 1) {
4584 new->baseTexture.sampler = Stage;
4586 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4590 if (NULL != oldTexture) {
4591 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4592 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4594 IWineD3DBaseTexture_Release(oldTexture);
4595 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4600 if(bindCount && old->baseTexture.sampler == Stage) {
4602 /* Have to do a search for the other sampler(s) where the texture is bound to
4603 * Shouldn't happen as long as apps bind a texture only to one stage
4605 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4606 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4607 if(This->updateStateBlock->textures[i] == oldTexture) {
4608 old->baseTexture.sampler = i;
4615 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4620 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4623 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4625 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4626 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4629 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4630 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4631 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4634 *ppTexture=This->stateBlock->textures[Stage];
4636 IWineD3DBaseTexture_AddRef(*ppTexture);
4638 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4646 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4647 IWineD3DSurface **ppBackBuffer) {
4648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4649 IWineD3DSwapChain *swapChain;
4652 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4654 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4655 if (hr == WINED3D_OK) {
4656 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4657 IWineD3DSwapChain_Release(swapChain);
4659 *ppBackBuffer = NULL;
4664 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4665 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4666 WARN("(%p) : stub, calling idirect3d for now\n", This);
4667 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4670 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4671 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4672 IWineD3DSwapChain *swapChain;
4675 if(iSwapChain > 0) {
4676 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4677 if (hr == WINED3D_OK) {
4678 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4679 IWineD3DSwapChain_Release(swapChain);
4681 FIXME("(%p) Error getting display mode\n", This);
4684 /* Don't read the real display mode,
4685 but return the stored mode instead. X11 can't change the color
4686 depth, and some apps are pretty angry if they SetDisplayMode from
4687 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4689 Also don't relay to the swapchain because with ddraw it's possible
4690 that there isn't a swapchain at all */
4691 pMode->Width = This->ddraw_width;
4692 pMode->Height = This->ddraw_height;
4693 pMode->Format = This->ddraw_format;
4694 pMode->RefreshRate = 0;
4702 * Stateblock related functions
4705 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4706 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4707 IWineD3DStateBlock *stateblock;
4710 TRACE("(%p)\n", This);
4712 if (This->isRecordingState) return WINED3DERR_INVALIDCALL;
4714 hr = IWineD3DDeviceImpl_CreateStateBlock(iface, WINED3DSBT_RECORDED, &stateblock, NULL);
4715 if (FAILED(hr)) return hr;
4717 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4718 This->updateStateBlock = (IWineD3DStateBlockImpl *)stateblock;
4719 This->isRecordingState = TRUE;
4721 TRACE("(%p) recording stateblock %p\n", This, stateblock);
4726 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4729 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4731 if (!This->isRecordingState) {
4732 WARN("(%p) not recording! returning error\n", This);
4733 *ppStateBlock = NULL;
4734 return WINED3DERR_INVALIDCALL;
4737 for (i = 0; i <= WINEHIGHEST_RENDER_STATE >> 5; ++i)
4739 DWORD map = object->changed.renderState[i];
4740 for (j = 0; map; map >>= 1, ++j)
4742 if (!(map & 1)) continue;
4744 object->contained_render_states[object->num_contained_render_states++] = (i << 5) | j;
4748 for (i = 0; i <= HIGHEST_TRANSFORMSTATE >> 5; ++i)
4750 DWORD map = object->changed.transform[i];
4751 for (j = 0; map; map >>= 1, ++j)
4753 if (!(map & 1)) continue;
4755 object->contained_transform_states[object->num_contained_transform_states++] = (i << 5) | j;
4758 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4759 if(object->changed.vertexShaderConstantsF[i]) {
4760 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4761 object->num_contained_vs_consts_f++;
4764 for(i = 0; i < MAX_CONST_I; i++) {
4765 if (object->changed.vertexShaderConstantsI & (1 << i))
4767 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4768 object->num_contained_vs_consts_i++;
4771 for(i = 0; i < MAX_CONST_B; i++) {
4772 if (object->changed.vertexShaderConstantsB & (1 << i))
4774 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4775 object->num_contained_vs_consts_b++;
4778 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i)
4780 if (object->changed.pixelShaderConstantsF[i])
4782 object->contained_ps_consts_f[object->num_contained_ps_consts_f] = i;
4783 ++object->num_contained_ps_consts_f;
4786 for(i = 0; i < MAX_CONST_I; i++) {
4787 if (object->changed.pixelShaderConstantsI & (1 << i))
4789 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4790 object->num_contained_ps_consts_i++;
4793 for(i = 0; i < MAX_CONST_B; i++) {
4794 if (object->changed.pixelShaderConstantsB & (1 << i))
4796 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4797 object->num_contained_ps_consts_b++;
4800 for(i = 0; i < MAX_TEXTURES; i++) {
4801 DWORD map = object->changed.textureState[i];
4803 for(j = 0; map; map >>= 1, ++j)
4805 if (!(map & 1)) continue;
4807 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4808 object->contained_tss_states[object->num_contained_tss_states].state = j;
4809 ++object->num_contained_tss_states;
4812 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4813 DWORD map = object->changed.samplerState[i];
4815 for (j = 0; map; map >>= 1, ++j)
4817 if (!(map & 1)) continue;
4819 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4820 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4821 ++object->num_contained_sampler_states;
4825 *ppStateBlock = (IWineD3DStateBlock*) object;
4826 This->isRecordingState = FALSE;
4827 This->updateStateBlock = This->stateBlock;
4828 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4829 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4830 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4835 * Scene related functions
4837 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4838 /* At the moment we have no need for any functionality at the beginning
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 TRACE("(%p)\n", This);
4844 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4845 return WINED3DERR_INVALIDCALL;
4847 This->inScene = TRUE;
4851 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 TRACE("(%p)\n", This);
4855 if(!This->inScene) {
4856 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4857 return WINED3DERR_INVALIDCALL;
4860 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4861 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4863 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4867 This->inScene = FALSE;
4871 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4872 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4873 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4875 IWineD3DSwapChain *swapChain = NULL;
4877 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4879 TRACE("(%p) Presenting the frame\n", This);
4881 for(i = 0 ; i < swapchains ; i ++) {
4883 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4884 TRACE("presentinng chain %d, %p\n", i, swapChain);
4885 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4886 IWineD3DSwapChain_Release(swapChain);
4892 /* Not called from the VTable (internal subroutine) */
4893 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4894 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4895 float Z, DWORD Stencil) {
4896 GLbitfield glMask = 0;
4898 WINED3DRECT curRect;
4900 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4901 UINT drawable_width, drawable_height;
4902 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4903 IWineD3DSwapChainImpl *swapchain = NULL;
4905 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4906 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4907 * for the cleared parts, and the untouched parts.
4909 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4910 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4911 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4912 * checking all this if the dest surface is in the drawable anyway.
4914 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4916 if(vp->X != 0 || vp->Y != 0 ||
4917 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
4918 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4921 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4922 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4923 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
4924 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
4925 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4928 if(Count > 0 && pRects && (
4929 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4930 pRects[0].x2 < target->currentDesc.Width ||
4931 pRects[0].y2 < target->currentDesc.Height)) {
4932 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
4939 target->get_drawable_size(target, &drawable_width, &drawable_height);
4941 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
4944 /* Only set the values up once, as they are not changing */
4945 if (Flags & WINED3DCLEAR_STENCIL) {
4946 glClearStencil(Stencil);
4947 checkGLcall("glClearStencil");
4948 glMask = glMask | GL_STENCIL_BUFFER_BIT;
4949 glStencilMask(0xFFFFFFFF);
4952 if (Flags & WINED3DCLEAR_ZBUFFER) {
4953 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
4954 glDepthMask(GL_TRUE);
4956 checkGLcall("glClearDepth");
4957 glMask = glMask | GL_DEPTH_BUFFER_BIT;
4958 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
4960 if (vp->X != 0 || vp->Y != 0 ||
4961 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
4962 surface_load_ds_location(This->stencilBufferTarget, location);
4964 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
4965 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
4966 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
4967 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
4968 surface_load_ds_location(This->stencilBufferTarget, location);
4970 else if (Count > 0 && pRects && (
4971 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
4972 pRects[0].x2 < depth_stencil->currentDesc.Width ||
4973 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
4974 surface_load_ds_location(This->stencilBufferTarget, location);
4978 if (Flags & WINED3DCLEAR_TARGET) {
4979 TRACE("Clearing screen with glClear to color %x\n", Color);
4980 glClearColor(D3DCOLOR_R(Color),
4984 checkGLcall("glClearColor");
4986 /* Clear ALL colors! */
4987 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
4988 glMask = glMask | GL_COLOR_BUFFER_BIT;
4991 vp_rect.left = vp->X;
4992 vp_rect.top = vp->Y;
4993 vp_rect.right = vp->X + vp->Width;
4994 vp_rect.bottom = vp->Y + vp->Height;
4995 if (!(Count > 0 && pRects)) {
4996 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
4997 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
4999 if(This->render_offscreen) {
5000 glScissor(vp_rect.left, vp_rect.top,
5001 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5003 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5004 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5006 checkGLcall("glScissor");
5008 checkGLcall("glClear");
5010 /* Now process each rect in turn */
5011 for (i = 0; i < Count; i++) {
5012 /* Note gl uses lower left, width/height */
5013 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5014 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5015 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5017 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5018 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5019 curRect.x1, (target->currentDesc.Height - curRect.y2),
5020 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5022 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5023 * The rectangle is not cleared, no error is returned, but further rectanlges are
5024 * still cleared if they are valid
5026 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5027 TRACE("Rectangle with negative dimensions, ignoring\n");
5031 if(This->render_offscreen) {
5032 glScissor(curRect.x1, curRect.y1,
5033 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5035 glScissor(curRect.x1, drawable_height - curRect.y2,
5036 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5038 checkGLcall("glScissor");
5041 checkGLcall("glClear");
5045 /* Restore the old values (why..?) */
5046 if (Flags & WINED3DCLEAR_STENCIL) {
5047 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5049 if (Flags & WINED3DCLEAR_TARGET) {
5050 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5051 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5052 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5053 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5054 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5056 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5057 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5059 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5061 if (Flags & WINED3DCLEAR_ZBUFFER) {
5062 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5063 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5064 surface_modify_ds_location(This->stencilBufferTarget, location);
5069 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5070 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5073 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5079 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5080 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5082 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5084 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5085 Count, pRects, Flags, Color, Z, Stencil);
5087 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5088 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5089 /* TODO: What about depth stencil buffers without stencil bits? */
5090 return WINED3DERR_INVALIDCALL;
5093 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5099 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5100 UINT PrimitiveCount) {
5102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5104 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5105 debug_d3dprimitivetype(PrimitiveType),
5106 StartVertex, PrimitiveCount);
5108 if(!This->stateBlock->vertexDecl) {
5109 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5110 return WINED3DERR_INVALIDCALL;
5113 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5114 if(This->stateBlock->streamIsUP) {
5115 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5116 This->stateBlock->streamIsUP = FALSE;
5119 if(This->stateBlock->loadBaseVertexIndex != 0) {
5120 This->stateBlock->loadBaseVertexIndex = 0;
5121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5123 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5124 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0/* NumVertices */, StartVertex /* start_idx */,
5125 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5129 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5130 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5131 WINED3DPRIMITIVETYPE PrimitiveType,
5132 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5136 IWineD3DIndexBuffer *pIB;
5137 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5140 pIB = This->stateBlock->pIndexData;
5142 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5143 * without an index buffer set. (The first time at least...)
5144 * D3D8 simply dies, but I doubt it can do much harm to return
5145 * D3DERR_INVALIDCALL there as well. */
5146 WARN("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5147 return WINED3DERR_INVALIDCALL;
5150 if(!This->stateBlock->vertexDecl) {
5151 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5152 return WINED3DERR_INVALIDCALL;
5155 if(This->stateBlock->streamIsUP) {
5156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5157 This->stateBlock->streamIsUP = FALSE;
5159 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5161 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5162 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5163 minIndex, NumVertices, startIndex, primCount);
5165 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5166 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5172 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5173 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5177 drawPrimitive(iface, PrimitiveType, primCount, NumVertices, startIndex,
5178 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5183 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5184 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5185 UINT VertexStreamZeroStride) {
5186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5187 IWineD3DVertexBuffer *vb;
5189 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5190 debug_d3dprimitivetype(PrimitiveType),
5191 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5193 if(!This->stateBlock->vertexDecl) {
5194 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5195 return WINED3DERR_INVALIDCALL;
5198 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5199 vb = This->stateBlock->streamSource[0];
5200 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5201 if(vb) IWineD3DVertexBuffer_Release(vb);
5202 This->stateBlock->streamOffset[0] = 0;
5203 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5204 This->stateBlock->streamIsUP = TRUE;
5205 This->stateBlock->loadBaseVertexIndex = 0;
5207 /* TODO: Only mark dirty if drawing from a different UP address */
5208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5210 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* NumVertices */,
5211 0 /* start_idx */, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5213 /* MSDN specifies stream zero settings must be set to NULL */
5214 This->stateBlock->streamStride[0] = 0;
5215 This->stateBlock->streamSource[0] = NULL;
5217 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5218 * the new stream sources or use UP drawing again
5223 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5224 UINT MinVertexIndex, UINT NumVertices,
5225 UINT PrimitiveCount, CONST void* pIndexData,
5226 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5227 UINT VertexStreamZeroStride) {
5229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5230 IWineD3DVertexBuffer *vb;
5231 IWineD3DIndexBuffer *ib;
5233 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5234 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5235 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5236 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5238 if(!This->stateBlock->vertexDecl) {
5239 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5240 return WINED3DERR_INVALIDCALL;
5243 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5249 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5250 vb = This->stateBlock->streamSource[0];
5251 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5252 if(vb) IWineD3DVertexBuffer_Release(vb);
5253 This->stateBlock->streamIsUP = TRUE;
5254 This->stateBlock->streamOffset[0] = 0;
5255 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5257 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5258 This->stateBlock->baseVertexIndex = 0;
5259 This->stateBlock->loadBaseVertexIndex = 0;
5260 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5264 drawPrimitive(iface, PrimitiveType, PrimitiveCount, NumVertices, 0 /* start_idx */, idxStride, pIndexData, MinVertexIndex);
5266 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5267 This->stateBlock->streamSource[0] = NULL;
5268 This->stateBlock->streamStride[0] = 0;
5269 ib = This->stateBlock->pIndexData;
5271 IWineD3DIndexBuffer_Release(ib);
5272 This->stateBlock->pIndexData = NULL;
5274 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5275 * SetStreamSource to specify a vertex buffer
5281 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5282 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5283 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5287 /* Mark the state dirty until we have nicer tracking
5288 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5291 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5292 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5293 This->stateBlock->baseVertexIndex = 0;
5294 This->up_strided = DrawPrimStrideData;
5295 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, NULL, 0);
5296 This->up_strided = NULL;
5300 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5301 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5302 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5303 WINED3DFORMAT IndexDataFormat)
5305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5306 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5308 /* Mark the state dirty until we have nicer tracking
5309 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5314 This->stateBlock->streamIsUP = TRUE;
5315 This->stateBlock->baseVertexIndex = 0;
5316 This->up_strided = DrawPrimStrideData;
5317 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* numindices */, 0 /* start_idx */, idxSize, pIndexData, 0 /* minindex */);
5318 This->up_strided = NULL;
5322 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5323 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5324 * not callable by the app directly no parameter validation checks are needed here.
5326 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5327 WINED3DLOCKED_BOX src;
5328 WINED3DLOCKED_BOX dst;
5330 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5332 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5333 * dirtification to improve loading performance.
5335 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5336 if(FAILED(hr)) return hr;
5337 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5339 IWineD3DVolume_UnlockBox(pSourceVolume);
5343 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5345 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5347 IWineD3DVolume_UnlockBox(pSourceVolume);
5349 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5354 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5355 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5356 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5357 HRESULT hr = WINED3D_OK;
5358 WINED3DRESOURCETYPE sourceType;
5359 WINED3DRESOURCETYPE destinationType;
5362 /* TODO: think about moving the code into IWineD3DBaseTexture */
5364 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5366 /* verify that the source and destination textures aren't NULL */
5367 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5368 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5369 This, pSourceTexture, pDestinationTexture);
5370 hr = WINED3DERR_INVALIDCALL;
5373 if (pSourceTexture == pDestinationTexture) {
5374 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5375 This, pSourceTexture, pDestinationTexture);
5376 hr = WINED3DERR_INVALIDCALL;
5378 /* Verify that the source and destination textures are the same type */
5379 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5380 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5382 if (sourceType != destinationType) {
5383 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5385 hr = WINED3DERR_INVALIDCALL;
5388 /* check that both textures have the identical numbers of levels */
5389 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5390 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5391 hr = WINED3DERR_INVALIDCALL;
5394 if (WINED3D_OK == hr) {
5396 /* Make sure that the destination texture is loaded */
5397 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5399 /* Update every surface level of the texture */
5400 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5402 switch (sourceType) {
5403 case WINED3DRTYPE_TEXTURE:
5405 IWineD3DSurface *srcSurface;
5406 IWineD3DSurface *destSurface;
5408 for (i = 0 ; i < levels ; ++i) {
5409 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5410 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5411 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5412 IWineD3DSurface_Release(srcSurface);
5413 IWineD3DSurface_Release(destSurface);
5414 if (WINED3D_OK != hr) {
5415 WARN("(%p) : Call to update surface failed\n", This);
5421 case WINED3DRTYPE_CUBETEXTURE:
5423 IWineD3DSurface *srcSurface;
5424 IWineD3DSurface *destSurface;
5425 WINED3DCUBEMAP_FACES faceType;
5427 for (i = 0 ; i < levels ; ++i) {
5428 /* Update each cube face */
5429 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5430 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5431 if (WINED3D_OK != hr) {
5432 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5434 TRACE("Got srcSurface %p\n", srcSurface);
5436 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5437 if (WINED3D_OK != hr) {
5438 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5440 TRACE("Got desrSurface %p\n", destSurface);
5442 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5443 IWineD3DSurface_Release(srcSurface);
5444 IWineD3DSurface_Release(destSurface);
5445 if (WINED3D_OK != hr) {
5446 WARN("(%p) : Call to update surface failed\n", This);
5454 case WINED3DRTYPE_VOLUMETEXTURE:
5456 IWineD3DVolume *srcVolume = NULL;
5457 IWineD3DVolume *destVolume = NULL;
5459 for (i = 0 ; i < levels ; ++i) {
5460 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5461 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5462 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5463 IWineD3DVolume_Release(srcVolume);
5464 IWineD3DVolume_Release(destVolume);
5465 if (WINED3D_OK != hr) {
5466 WARN("(%p) : Call to update volume failed\n", This);
5474 FIXME("(%p) : Unsupported source and destination type\n", This);
5475 hr = WINED3DERR_INVALIDCALL;
5482 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5483 IWineD3DSwapChain *swapChain;
5485 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5486 if(hr == WINED3D_OK) {
5487 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5488 IWineD3DSwapChain_Release(swapChain);
5493 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5494 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5495 IWineD3DBaseTextureImpl *texture;
5496 const struct GlPixelFormatDesc *gl_info;
5499 TRACE("(%p) : %p\n", This, pNumPasses);
5501 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5502 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5503 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5504 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5506 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5507 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5508 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5511 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5512 if(!texture) continue;
5513 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5514 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5516 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5517 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5520 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5521 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5524 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5525 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5526 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5531 /* return a sensible default */
5534 TRACE("returning D3D_OK\n");
5538 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5542 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5543 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5544 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5545 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5550 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5554 PALETTEENTRY **palettes;
5556 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5558 if (PaletteNumber >= MAX_PALETTES) {
5559 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5560 return WINED3DERR_INVALIDCALL;
5563 if (PaletteNumber >= This->NumberOfPalettes) {
5564 NewSize = This->NumberOfPalettes;
5567 } while(PaletteNumber >= NewSize);
5568 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5570 ERR("Out of memory!\n");
5571 return E_OUTOFMEMORY;
5573 This->palettes = palettes;
5574 This->NumberOfPalettes = NewSize;
5577 if (!This->palettes[PaletteNumber]) {
5578 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5579 if (!This->palettes[PaletteNumber]) {
5580 ERR("Out of memory!\n");
5581 return E_OUTOFMEMORY;
5585 for (j = 0; j < 256; ++j) {
5586 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5587 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5588 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5589 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5591 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5592 TRACE("(%p) : returning\n", This);
5596 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5599 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5600 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5601 /* What happens in such situation isn't documented; Native seems to silently abort
5602 on such conditions. Return Invalid Call. */
5603 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5604 return WINED3DERR_INVALIDCALL;
5606 for (j = 0; j < 256; ++j) {
5607 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5608 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5609 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5610 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5612 TRACE("(%p) : returning\n", This);
5616 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5617 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5618 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5619 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5620 (tested with reference rasterizer). Return Invalid Call. */
5621 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5622 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5623 return WINED3DERR_INVALIDCALL;
5625 /*TODO: stateblocks */
5626 if (This->currentPalette != PaletteNumber) {
5627 This->currentPalette = PaletteNumber;
5628 dirtify_p8_texture_samplers(This);
5630 TRACE("(%p) : returning\n", This);
5634 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5635 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5636 if (PaletteNumber == NULL) {
5637 WARN("(%p) : returning Invalid Call\n", This);
5638 return WINED3DERR_INVALIDCALL;
5640 /*TODO: stateblocks */
5641 *PaletteNumber = This->currentPalette;
5642 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5646 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5651 FIXME("(%p) : stub\n", This);
5655 This->softwareVertexProcessing = bSoftware;
5660 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5661 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5665 FIXME("(%p) : stub\n", This);
5668 return This->softwareVertexProcessing;
5672 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5674 IWineD3DSwapChain *swapChain;
5677 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5679 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5680 if(hr == WINED3D_OK){
5681 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5682 IWineD3DSwapChain_Release(swapChain);
5684 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5690 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5693 if(nSegments != 0.0f) {
5696 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5703 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5708 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5714 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5716 /** TODO: remove casts to IWineD3DSurfaceImpl
5717 * NOTE: move code to surface to accomplish this
5718 ****************************************/
5719 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5720 int srcWidth, srcHeight;
5721 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5722 WINED3DFORMAT destFormat, srcFormat;
5724 int srcLeft, destLeft, destTop;
5725 WINED3DPOOL srcPool, destPool;
5727 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5728 glDescriptor *glDescription = NULL;
5732 CONVERT_TYPES convert = NO_CONVERSION;
5734 WINED3DSURFACE_DESC winedesc;
5736 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5737 memset(&winedesc, 0, sizeof(winedesc));
5738 winedesc.Width = &srcSurfaceWidth;
5739 winedesc.Height = &srcSurfaceHeight;
5740 winedesc.Pool = &srcPool;
5741 winedesc.Format = &srcFormat;
5743 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5745 winedesc.Width = &destSurfaceWidth;
5746 winedesc.Height = &destSurfaceHeight;
5747 winedesc.Pool = &destPool;
5748 winedesc.Format = &destFormat;
5749 winedesc.Size = &destSize;
5751 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5753 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5754 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5755 return WINED3DERR_INVALIDCALL;
5758 /* This call loads the opengl surface directly, instead of copying the surface to the
5759 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5760 * copy in sysmem and use regular surface loading.
5762 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5763 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5764 if(convert != NO_CONVERSION) {
5765 return IWineD3DSurface_BltFast(pDestinationSurface,
5766 pDestPoint ? pDestPoint->x : 0,
5767 pDestPoint ? pDestPoint->y : 0,
5768 pSourceSurface, pSourceRect, 0);
5771 if (destFormat == WINED3DFMT_UNKNOWN) {
5772 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5773 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5775 /* Get the update surface description */
5776 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5779 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5782 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5783 checkGLcall("glActiveTextureARB");
5786 /* Make sure the surface is loaded and up to date */
5787 IWineD3DSurface_PreLoad(pDestinationSurface);
5788 IWineD3DSurface_BindTexture(pDestinationSurface);
5790 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5792 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5793 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5794 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5795 srcLeft = pSourceRect ? pSourceRect->left : 0;
5796 destLeft = pDestPoint ? pDestPoint->x : 0;
5797 destTop = pDestPoint ? pDestPoint->y : 0;
5800 /* This function doesn't support compressed textures
5801 the pitch is just bytesPerPixel * width */
5802 if(srcWidth != srcSurfaceWidth || srcLeft ){
5803 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5804 offset += srcLeft * pSrcSurface->bytesPerPixel;
5805 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5807 /* TODO DXT formats */
5809 if(pSourceRect != NULL && pSourceRect->top != 0){
5810 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5812 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5813 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5814 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5817 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5819 /* need to lock the surface to get the data */
5820 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5825 /* TODO: Cube and volume support */
5827 /* not a whole row so we have to do it a line at a time */
5830 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5831 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5833 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5835 glTexSubImage2D(glDescription->target
5836 ,glDescription->level
5841 ,glDescription->glFormat
5842 ,glDescription->glType
5843 ,data /* could be quicker using */
5848 } else { /* Full width, so just write out the whole texture */
5849 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5851 if (WINED3DFMT_DXT1 == destFormat ||
5852 WINED3DFMT_DXT2 == destFormat ||
5853 WINED3DFMT_DXT3 == destFormat ||
5854 WINED3DFMT_DXT4 == destFormat ||
5855 WINED3DFMT_DXT5 == destFormat) {
5856 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5857 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5858 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5859 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5860 } if (destFormat != srcFormat) {
5861 FIXME("Updating mixed format compressed texture is not curretly support\n");
5863 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5864 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5867 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5872 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5873 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5876 checkGLcall("glTexSubImage2D");
5880 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5881 sampler = This->rev_tex_unit_map[0];
5882 if (sampler != -1) {
5883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5889 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5890 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5891 struct WineD3DRectPatch *patch;
5895 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5897 if(!(Handle || pRectPatchInfo)) {
5898 /* TODO: Write a test for the return value, thus the FIXME */
5899 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5900 return WINED3DERR_INVALIDCALL;
5904 i = PATCHMAP_HASHFUNC(Handle);
5906 LIST_FOR_EACH(e, &This->patches[i]) {
5907 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5908 if(patch->Handle == Handle) {
5915 TRACE("Patch does not exist. Creating a new one\n");
5916 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5917 patch->Handle = Handle;
5918 list_add_head(&This->patches[i], &patch->entry);
5920 TRACE("Found existing patch %p\n", patch);
5923 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5924 * attributes we have to tesselate, read back, and draw. This needs a patch
5925 * management structure instance. Create one.
5927 * A possible improvement is to check if a vertex shader is used, and if not directly
5930 FIXME("Drawing an uncached patch. This is slow\n");
5931 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5934 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5935 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5936 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5938 TRACE("Tesselation density or patch info changed, retesselating\n");
5940 if(pRectPatchInfo) {
5941 patch->RectPatchInfo = *pRectPatchInfo;
5943 patch->numSegs[0] = pNumSegs[0];
5944 patch->numSegs[1] = pNumSegs[1];
5945 patch->numSegs[2] = pNumSegs[2];
5946 patch->numSegs[3] = pNumSegs[3];
5948 hr = tesselate_rectpatch(This, patch);
5950 WARN("Patch tesselation failed\n");
5952 /* Do not release the handle to store the params of the patch */
5954 HeapFree(GetProcessHeap(), 0, patch);
5960 This->currentPatch = patch;
5961 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
5962 This->currentPatch = NULL;
5964 /* Destroy uncached patches */
5966 HeapFree(GetProcessHeap(), 0, patch->mem);
5967 HeapFree(GetProcessHeap(), 0, patch);
5972 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5974 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
5975 FIXME("(%p) : Stub\n", This);
5979 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
5980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5982 struct WineD3DRectPatch *patch;
5984 TRACE("(%p) Handle(%d)\n", This, Handle);
5986 i = PATCHMAP_HASHFUNC(Handle);
5987 LIST_FOR_EACH(e, &This->patches[i]) {
5988 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5989 if(patch->Handle == Handle) {
5990 TRACE("Deleting patch %p\n", patch);
5991 list_remove(&patch->entry);
5992 HeapFree(GetProcessHeap(), 0, patch->mem);
5993 HeapFree(GetProcessHeap(), 0, patch);
5998 /* TODO: Write a test for the return value */
5999 FIXME("Attempt to destroy nonexistent patch\n");
6000 return WINED3DERR_INVALIDCALL;
6003 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6005 IWineD3DSwapChain *swapchain;
6007 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6008 if (SUCCEEDED(hr)) {
6009 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6016 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6017 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6018 IWineD3DSwapChain *swapchain;
6020 swapchain = get_swapchain(surface);
6024 TRACE("Surface %p is onscreen\n", surface);
6026 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6028 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6029 buffer = surface_get_gl_buffer(surface, swapchain);
6030 glDrawBuffer(buffer);
6031 checkGLcall("glDrawBuffer()");
6033 TRACE("Surface %p is offscreen\n", surface);
6035 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6037 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6038 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6039 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6040 checkGLcall("glFramebufferRenderbufferEXT");
6044 glEnable(GL_SCISSOR_TEST);
6046 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6048 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6049 rect->x2 - rect->x1, rect->y2 - rect->y1);
6051 checkGLcall("glScissor");
6052 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6054 glDisable(GL_SCISSOR_TEST);
6056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6058 glDisable(GL_BLEND);
6059 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6061 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6062 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6064 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6065 glClear(GL_COLOR_BUFFER_BIT);
6066 checkGLcall("glClear");
6068 if (This->activeContext->current_fbo) {
6069 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6071 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6072 checkGLcall("glBindFramebuffer()");
6075 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6076 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6077 glDrawBuffer(GL_BACK);
6078 checkGLcall("glDrawBuffer()");
6084 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6085 unsigned int r, g, b, a;
6088 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6089 destfmt == WINED3DFMT_R8G8B8)
6092 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6094 a = (color & 0xff000000) >> 24;
6095 r = (color & 0x00ff0000) >> 16;
6096 g = (color & 0x0000ff00) >> 8;
6097 b = (color & 0x000000ff) >> 0;
6101 case WINED3DFMT_R5G6B5:
6102 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6109 TRACE("Returning %08x\n", ret);
6112 case WINED3DFMT_X1R5G5B5:
6113 case WINED3DFMT_A1R5G5B5:
6122 TRACE("Returning %08x\n", ret);
6126 TRACE("Returning %08x\n", a);
6129 case WINED3DFMT_X4R4G4B4:
6130 case WINED3DFMT_A4R4G4B4:
6139 TRACE("Returning %08x\n", ret);
6142 case WINED3DFMT_R3G3B2:
6149 TRACE("Returning %08x\n", ret);
6152 case WINED3DFMT_X8B8G8R8:
6153 case WINED3DFMT_A8B8G8R8:
6158 TRACE("Returning %08x\n", ret);
6161 case WINED3DFMT_A2R10G10B10:
6163 r = (r * 1024) / 256;
6164 g = (g * 1024) / 256;
6165 b = (b * 1024) / 256;
6170 TRACE("Returning %08x\n", ret);
6173 case WINED3DFMT_A2B10G10R10:
6175 r = (r * 1024) / 256;
6176 g = (g * 1024) / 256;
6177 b = (b * 1024) / 256;
6182 TRACE("Returning %08x\n", ret);
6186 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6191 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6193 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6195 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6197 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6198 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6199 return WINED3DERR_INVALIDCALL;
6202 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6203 color_fill_fbo(iface, pSurface, pRect, color);
6206 /* Just forward this to the DirectDraw blitting engine */
6207 memset(&BltFx, 0, sizeof(BltFx));
6208 BltFx.dwSize = sizeof(BltFx);
6209 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6210 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6211 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6215 /* rendertarget and depth stencil functions */
6216 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6217 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6219 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6220 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6221 return WINED3DERR_INVALIDCALL;
6224 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6225 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6226 /* Note inc ref on returned surface */
6227 if(*ppRenderTarget != NULL)
6228 IWineD3DSurface_AddRef(*ppRenderTarget);
6232 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6234 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6235 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6236 IWineD3DSwapChainImpl *Swapchain;
6239 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6241 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6242 if(hr != WINED3D_OK) {
6243 ERR("Can't get the swapchain\n");
6247 /* Make sure to release the swapchain */
6248 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6250 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6251 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6252 return WINED3DERR_INVALIDCALL;
6254 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6255 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6256 return WINED3DERR_INVALIDCALL;
6259 if(Swapchain->frontBuffer != Front) {
6260 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6262 if(Swapchain->frontBuffer)
6263 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6264 Swapchain->frontBuffer = Front;
6266 if(Swapchain->frontBuffer) {
6267 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6271 if(Back && !Swapchain->backBuffer) {
6272 /* We need memory for the back buffer array - only one back buffer this way */
6273 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6274 if(!Swapchain->backBuffer) {
6275 ERR("Out of memory\n");
6276 return E_OUTOFMEMORY;
6280 if(Swapchain->backBuffer[0] != Back) {
6281 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6283 /* What to do about the context here in the case of multithreading? Not sure.
6284 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6287 if(!Swapchain->backBuffer[0]) {
6288 /* GL was told to draw to the front buffer at creation,
6291 glDrawBuffer(GL_BACK);
6292 checkGLcall("glDrawBuffer(GL_BACK)");
6293 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6294 Swapchain->presentParms.BackBufferCount = 1;
6296 /* That makes problems - disable for now */
6297 /* glDrawBuffer(GL_FRONT); */
6298 checkGLcall("glDrawBuffer(GL_FRONT)");
6299 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6300 Swapchain->presentParms.BackBufferCount = 0;
6304 if(Swapchain->backBuffer[0])
6305 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6306 Swapchain->backBuffer[0] = Back;
6308 if(Swapchain->backBuffer[0]) {
6309 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6311 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6312 Swapchain->backBuffer = NULL;
6320 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6322 *ppZStencilSurface = This->stencilBufferTarget;
6323 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6325 if(*ppZStencilSurface != NULL) {
6326 /* Note inc ref on returned surface */
6327 IWineD3DSurface_AddRef(*ppZStencilSurface);
6330 return WINED3DERR_NOTFOUND;
6334 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6335 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6338 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6339 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6341 POINT offset = {0, 0};
6343 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6344 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6345 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6346 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6349 case WINED3DTEXF_LINEAR:
6350 gl_filter = GL_LINEAR;
6354 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6355 case WINED3DTEXF_NONE:
6356 case WINED3DTEXF_POINT:
6357 gl_filter = GL_NEAREST;
6361 /* Attach src surface to src fbo */
6362 src_swapchain = get_swapchain(src_surface);
6363 if (src_swapchain) {
6364 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6366 TRACE("Source surface %p is onscreen\n", src_surface);
6367 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6368 /* Make sure the drawable is up to date. In the offscreen case
6369 * attach_surface_fbo() implicitly takes care of this. */
6370 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6372 if(buffer == GL_FRONT) {
6375 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6376 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6377 h = windowsize.bottom - windowsize.top;
6378 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6379 src_rect->y1 = offset.y + h - src_rect->y1;
6380 src_rect->y2 = offset.y + h - src_rect->y2;
6382 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6383 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6387 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6388 glReadBuffer(buffer);
6389 checkGLcall("glReadBuffer()");
6391 TRACE("Source surface %p is offscreen\n", src_surface);
6393 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6394 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6395 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6396 checkGLcall("glReadBuffer()");
6397 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6398 checkGLcall("glFramebufferRenderbufferEXT");
6402 /* Attach dst surface to dst fbo */
6403 dst_swapchain = get_swapchain(dst_surface);
6404 if (dst_swapchain) {
6405 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6407 TRACE("Destination surface %p is onscreen\n", dst_surface);
6408 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6409 /* Make sure the drawable is up to date. In the offscreen case
6410 * attach_surface_fbo() implicitly takes care of this. */
6411 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6413 if(buffer == GL_FRONT) {
6416 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6417 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6418 h = windowsize.bottom - windowsize.top;
6419 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6420 dst_rect->y1 = offset.y + h - dst_rect->y1;
6421 dst_rect->y2 = offset.y + h - dst_rect->y2;
6423 /* Screen coords = window coords, surface height = window height */
6424 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6425 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6429 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6430 glDrawBuffer(buffer);
6431 checkGLcall("glDrawBuffer()");
6433 TRACE("Destination surface %p is offscreen\n", dst_surface);
6435 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6436 if(!src_swapchain) {
6437 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6441 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6442 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6443 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6444 checkGLcall("glDrawBuffer()");
6445 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6446 checkGLcall("glFramebufferRenderbufferEXT");
6448 glDisable(GL_SCISSOR_TEST);
6449 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6452 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6453 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6454 checkGLcall("glBlitFramebuffer()");
6456 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6457 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6458 checkGLcall("glBlitFramebuffer()");
6461 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6463 if (This->activeContext->current_fbo) {
6464 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6466 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6467 checkGLcall("glBindFramebuffer()");
6470 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6471 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6472 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6473 glDrawBuffer(GL_BACK);
6474 checkGLcall("glDrawBuffer()");
6479 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6480 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6481 WINED3DVIEWPORT viewport;
6483 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6485 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6486 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6487 This, RenderTargetIndex, GL_LIMITS(buffers));
6488 return WINED3DERR_INVALIDCALL;
6491 /* MSDN says that null disables the render target
6492 but a device must always be associated with a render target
6493 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6495 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6496 FIXME("Trying to set render target 0 to NULL\n");
6497 return WINED3DERR_INVALIDCALL;
6499 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6500 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);
6501 return WINED3DERR_INVALIDCALL;
6504 /* If we are trying to set what we already have, don't bother */
6505 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6506 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6509 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6510 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6511 This->render_targets[RenderTargetIndex] = pRenderTarget;
6513 /* Render target 0 is special */
6514 if(RenderTargetIndex == 0) {
6515 /* Finally, reset the viewport as the MSDN states. */
6516 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6517 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6520 viewport.MaxZ = 1.0f;
6521 viewport.MinZ = 0.0f;
6522 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6523 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6524 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6526 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6531 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 HRESULT hr = WINED3D_OK;
6534 IWineD3DSurface *tmp;
6536 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6538 if (pNewZStencil == This->stencilBufferTarget) {
6539 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6541 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6542 * depending on the renter target implementation being used.
6543 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6544 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6545 * stencil buffer and incur an extra memory overhead
6546 ******************************************************/
6548 if (This->stencilBufferTarget) {
6549 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6550 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6551 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6553 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6554 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6555 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6559 tmp = This->stencilBufferTarget;
6560 This->stencilBufferTarget = pNewZStencil;
6561 /* should we be calling the parent or the wined3d surface? */
6562 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6563 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6566 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6567 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6568 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6570 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6577 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6578 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6580 /* TODO: the use of Impl is deprecated. */
6581 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6582 WINED3DLOCKED_RECT lockedRect;
6584 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6586 /* some basic validation checks */
6587 if(This->cursorTexture) {
6588 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6590 glDeleteTextures(1, &This->cursorTexture);
6592 This->cursorTexture = 0;
6595 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6596 This->haveHardwareCursor = TRUE;
6598 This->haveHardwareCursor = FALSE;
6601 WINED3DLOCKED_RECT rect;
6603 /* MSDN: Cursor must be A8R8G8B8 */
6604 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6605 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6606 return WINED3DERR_INVALIDCALL;
6609 /* MSDN: Cursor must be smaller than the display mode */
6610 if(pSur->currentDesc.Width > This->ddraw_width ||
6611 pSur->currentDesc.Height > This->ddraw_height) {
6612 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);
6613 return WINED3DERR_INVALIDCALL;
6616 if (!This->haveHardwareCursor) {
6617 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6619 /* Do not store the surface's pointer because the application may
6620 * release it after setting the cursor image. Windows doesn't
6621 * addref the set surface, so we can't do this either without
6622 * creating circular refcount dependencies. Copy out the gl texture
6625 This->cursorWidth = pSur->currentDesc.Width;
6626 This->cursorHeight = pSur->currentDesc.Height;
6627 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6629 const struct GlPixelFormatDesc *glDesc;
6630 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6631 char *mem, *bits = (char *)rect.pBits;
6632 GLint intfmt = glDesc->glInternal;
6633 GLint format = glDesc->glFormat;
6634 GLint type = glDesc->glType;
6635 INT height = This->cursorHeight;
6636 INT width = This->cursorWidth;
6637 INT bpp = tableEntry->bpp;
6640 /* Reformat the texture memory (pitch and width can be
6642 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6643 for(i = 0; i < height; i++)
6644 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6645 IWineD3DSurface_UnlockRect(pCursorBitmap);
6648 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6649 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6650 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6653 /* Make sure that a proper texture unit is selected */
6654 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6655 checkGLcall("glActiveTextureARB");
6656 sampler = This->rev_tex_unit_map[0];
6657 if (sampler != -1) {
6658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6660 /* Create a new cursor texture */
6661 glGenTextures(1, &This->cursorTexture);
6662 checkGLcall("glGenTextures");
6663 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6664 checkGLcall("glBindTexture");
6665 /* Copy the bitmap memory into the cursor texture */
6666 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6667 HeapFree(GetProcessHeap(), 0, mem);
6668 checkGLcall("glTexImage2D");
6670 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6671 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6672 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6679 FIXME("A cursor texture was not returned.\n");
6680 This->cursorTexture = 0;
6685 /* Draw a hardware cursor */
6686 ICONINFO cursorInfo;
6688 /* Create and clear maskBits because it is not needed for
6689 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6691 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6692 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6693 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6694 WINED3DLOCK_NO_DIRTY_UPDATE |
6695 WINED3DLOCK_READONLY
6697 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6698 pSur->currentDesc.Height);
6700 cursorInfo.fIcon = FALSE;
6701 cursorInfo.xHotspot = XHotSpot;
6702 cursorInfo.yHotspot = YHotSpot;
6703 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6704 pSur->currentDesc.Height, 1,
6706 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6707 pSur->currentDesc.Height, 1,
6708 32, lockedRect.pBits);
6709 IWineD3DSurface_UnlockRect(pCursorBitmap);
6710 /* Create our cursor and clean up. */
6711 cursor = CreateIconIndirect(&cursorInfo);
6713 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6714 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6715 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6716 This->hardwareCursor = cursor;
6717 HeapFree(GetProcessHeap(), 0, maskBits);
6721 This->xHotSpot = XHotSpot;
6722 This->yHotSpot = YHotSpot;
6726 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6728 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6730 This->xScreenSpace = XScreenSpace;
6731 This->yScreenSpace = YScreenSpace;
6737 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6739 BOOL oldVisible = This->bCursorVisible;
6742 TRACE("(%p) : visible(%d)\n", This, bShow);
6745 * When ShowCursor is first called it should make the cursor appear at the OS's last
6746 * known cursor position. Because of this, some applications just repetitively call
6747 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6750 This->xScreenSpace = pt.x;
6751 This->yScreenSpace = pt.y;
6753 if (This->haveHardwareCursor) {
6754 This->bCursorVisible = bShow;
6756 SetCursor(This->hardwareCursor);
6762 if (This->cursorTexture)
6763 This->bCursorVisible = bShow;
6769 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6771 IWineD3DResourceImpl *resource;
6772 TRACE("(%p) : state (%u)\n", This, This->state);
6774 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6775 switch (This->state) {
6778 case WINED3DERR_DEVICELOST:
6780 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6781 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6782 return WINED3DERR_DEVICENOTRESET;
6784 return WINED3DERR_DEVICELOST;
6786 case WINED3DERR_DRIVERINTERNALERROR:
6787 return WINED3DERR_DRIVERINTERNALERROR;
6791 return WINED3DERR_DRIVERINTERNALERROR;
6795 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6796 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6797 /** FIXME: Resource tracking needs to be done,
6798 * The closes we can do to this is set the priorities of all managed textures low
6799 * and then reset them.
6800 ***********************************************************/
6801 FIXME("(%p) : stub\n", This);
6805 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6807 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6809 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6810 if(surface->Flags & SFLAG_DIBSECTION) {
6811 /* Release the DC */
6812 SelectObject(surface->hDC, surface->dib.holdbitmap);
6813 DeleteDC(surface->hDC);
6814 /* Release the DIB section */
6815 DeleteObject(surface->dib.DIBsection);
6816 surface->dib.bitmap_data = NULL;
6817 surface->resource.allocatedMemory = NULL;
6818 surface->Flags &= ~SFLAG_DIBSECTION;
6820 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6821 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6822 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6823 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6824 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6825 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6827 surface->pow2Width = surface->pow2Height = 1;
6828 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6829 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6831 surface->glRect.left = 0;
6832 surface->glRect.top = 0;
6833 surface->glRect.right = surface->pow2Width;
6834 surface->glRect.bottom = surface->pow2Height;
6836 if(surface->glDescription.textureName) {
6837 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6839 glDeleteTextures(1, &surface->glDescription.textureName);
6841 surface->glDescription.textureName = 0;
6842 surface->Flags &= ~SFLAG_CLIENT;
6844 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6845 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6846 surface->Flags |= SFLAG_NONPOW2;
6848 surface->Flags &= ~SFLAG_NONPOW2;
6850 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6851 surface->resource.allocatedMemory = NULL;
6852 surface->resource.heapMemory = NULL;
6853 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6854 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6855 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6856 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6858 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6862 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6863 TRACE("Unloading resource %p\n", resource);
6864 IWineD3DResource_UnLoad(resource);
6865 IWineD3DResource_Release(resource);
6869 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6872 WINED3DDISPLAYMODE m;
6875 /* All Windowed modes are supported, as is leaving the current mode */
6876 if(pp->Windowed) return TRUE;
6877 if(!pp->BackBufferWidth) return TRUE;
6878 if(!pp->BackBufferHeight) return TRUE;
6880 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6881 for(i = 0; i < count; i++) {
6882 memset(&m, 0, sizeof(m));
6883 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6885 ERR("EnumAdapterModes failed\n");
6887 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
6888 /* Mode found, it is supported */
6892 /* Mode not found -> not supported */
6896 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6898 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6900 IWineD3DBaseShaderImpl *shader;
6902 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
6903 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
6904 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
6908 if(This->depth_blt_texture) {
6909 glDeleteTextures(1, &This->depth_blt_texture);
6910 This->depth_blt_texture = 0;
6912 if (This->depth_blt_rb) {
6913 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
6914 This->depth_blt_rb = 0;
6915 This->depth_blt_rb_w = 0;
6916 This->depth_blt_rb_h = 0;
6920 This->blitter->free_private(iface);
6921 This->frag_pipe->free_private(iface);
6922 This->shader_backend->shader_free_private(iface);
6925 for (i = 0; i < GL_LIMITS(textures); i++) {
6926 /* Textures are recreated below */
6927 glDeleteTextures(1, &This->dummyTextureName[i]);
6928 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
6929 This->dummyTextureName[i] = 0;
6933 while(This->numContexts) {
6934 DestroyContext(This, This->contexts[0]);
6936 This->activeContext = NULL;
6937 HeapFree(GetProcessHeap(), 0, swapchain->context);
6938 swapchain->context = NULL;
6939 swapchain->num_contexts = 0;
6942 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
6943 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6944 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
6946 IWineD3DSurfaceImpl *target;
6948 /* Recreate the primary swapchain's context */
6949 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
6950 if(swapchain->backBuffer) {
6951 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
6953 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
6955 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
6956 &swapchain->presentParms);
6957 swapchain->num_contexts = 1;
6958 This->activeContext = swapchain->context[0];
6960 create_dummy_textures(This);
6962 hr = This->shader_backend->shader_alloc_private(iface);
6964 ERR("Failed to recreate shader private data\n");
6967 hr = This->frag_pipe->alloc_private(iface);
6969 TRACE("Fragment pipeline private data couldn't be allocated\n");
6972 hr = This->blitter->alloc_private(iface);
6974 TRACE("Blitter private data couldn't be allocated\n");
6981 This->blitter->free_private(iface);
6982 This->frag_pipe->free_private(iface);
6983 This->shader_backend->shader_free_private(iface);
6987 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
6988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6989 IWineD3DSwapChainImpl *swapchain;
6991 BOOL DisplayModeChanged = FALSE;
6992 WINED3DDISPLAYMODE mode;
6993 TRACE("(%p)\n", This);
6995 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
6997 ERR("Failed to get the first implicit swapchain\n");
7001 if(!is_display_mode_supported(This, pPresentationParameters)) {
7002 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7003 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7004 pPresentationParameters->BackBufferHeight);
7005 return WINED3DERR_INVALIDCALL;
7008 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7009 * on an existing gl context, so there's no real need for recreation.
7011 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7013 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7015 TRACE("New params:\n");
7016 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7017 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7018 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7019 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7020 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7021 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7022 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7023 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7024 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7025 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7026 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7027 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7028 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7030 /* No special treatment of these parameters. Just store them */
7031 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7032 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7033 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7034 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7036 /* What to do about these? */
7037 if(pPresentationParameters->BackBufferCount != 0 &&
7038 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7039 ERR("Cannot change the back buffer count yet\n");
7041 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7042 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7043 ERR("Cannot change the back buffer format yet\n");
7045 if(pPresentationParameters->hDeviceWindow != NULL &&
7046 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7047 ERR("Cannot change the device window yet\n");
7049 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7050 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7051 return WINED3DERR_INVALIDCALL;
7054 /* Reset the depth stencil */
7055 if (pPresentationParameters->EnableAutoDepthStencil)
7056 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7058 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7060 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7062 if(pPresentationParameters->Windowed) {
7063 mode.Width = swapchain->orig_width;
7064 mode.Height = swapchain->orig_height;
7065 mode.RefreshRate = 0;
7066 mode.Format = swapchain->presentParms.BackBufferFormat;
7068 mode.Width = pPresentationParameters->BackBufferWidth;
7069 mode.Height = pPresentationParameters->BackBufferHeight;
7070 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7071 mode.Format = swapchain->presentParms.BackBufferFormat;
7074 /* Should Width == 800 && Height == 0 set 800x600? */
7075 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7076 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7077 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7081 if(!pPresentationParameters->Windowed) {
7082 DisplayModeChanged = TRUE;
7084 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7085 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7087 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7088 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7089 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7091 if(This->auto_depth_stencil_buffer) {
7092 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7096 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7097 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7098 DisplayModeChanged) {
7100 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7102 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7103 if(swapchain->presentParms.Windowed) {
7104 /* switch from windowed to fs */
7105 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7106 pPresentationParameters->BackBufferWidth,
7107 pPresentationParameters->BackBufferHeight);
7109 /* Fullscreen -> fullscreen mode change */
7110 MoveWindow(swapchain->win_handle, 0, 0,
7111 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7114 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7115 /* Fullscreen -> windowed switch */
7116 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7118 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7119 } else if(!pPresentationParameters->Windowed) {
7120 DWORD style = This->style, exStyle = This->exStyle;
7121 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7122 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7123 * Reset to clear up their mess. Guild Wars also loses the device during that.
7127 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7128 pPresentationParameters->BackBufferWidth,
7129 pPresentationParameters->BackBufferHeight);
7130 This->style = style;
7131 This->exStyle = exStyle;
7134 TRACE("Resetting stateblock\n");
7135 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock);
7136 IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->stateBlock);
7138 /* Note: No parent needed for initial internal stateblock */
7139 hr = IWineD3DDevice_CreateStateBlock(iface, WINED3DSBT_INIT, (IWineD3DStateBlock **)&This->stateBlock, NULL);
7140 if (FAILED(hr)) ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7141 else TRACE("Created stateblock %p\n", This->stateBlock);
7142 This->updateStateBlock = This->stateBlock;
7143 IWineD3DStateBlock_AddRef((IWineD3DStateBlock *)This->updateStateBlock);
7145 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7147 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7150 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7151 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7153 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7159 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7161 /** FIXME: always true at the moment **/
7162 if(!bEnableDialogs) {
7163 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7169 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7171 TRACE("(%p) : pParameters %p\n", This, pParameters);
7173 *pParameters = This->createParms;
7177 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7178 IWineD3DSwapChain *swapchain;
7180 TRACE("Relaying to swapchain\n");
7182 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7183 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7184 IWineD3DSwapChain_Release(swapchain);
7189 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7190 IWineD3DSwapChain *swapchain;
7192 TRACE("Relaying to swapchain\n");
7194 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7195 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7196 IWineD3DSwapChain_Release(swapchain);
7202 /** ********************************************************
7203 * Notification functions
7204 ** ********************************************************/
7205 /** This function must be called in the release of a resource when ref == 0,
7206 * the contents of resource must still be correct,
7207 * any handles to other resource held by the caller must be closed
7208 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7209 *****************************************************/
7210 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7213 TRACE("(%p) : Adding Resource %p\n", This, resource);
7214 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7217 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7220 TRACE("(%p) : Removing resource %p\n", This, resource);
7222 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7226 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7228 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7231 TRACE("(%p) : resource %p\n", This, resource);
7233 context_resource_released(iface, resource, type);
7236 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7237 case WINED3DRTYPE_SURFACE: {
7240 /* Cleanup any FBO attachments if d3d is enabled */
7241 if(This->d3d_initialized) {
7242 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7243 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7245 TRACE("Last active render target destroyed\n");
7246 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7247 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7248 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7249 * and the lastActiveRenderTarget member shouldn't matter
7252 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7253 TRACE("Activating primary back buffer\n");
7254 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7255 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7256 /* Single buffering environment */
7257 TRACE("Activating primary front buffer\n");
7258 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7260 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7261 /* Implicit render target destroyed, that means the device is being destroyed
7262 * whatever we set here, it shouldn't matter
7264 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7267 /* May happen during ddraw uninitialization */
7268 TRACE("Render target set, but swapchain does not exist!\n");
7269 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7273 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7274 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7275 This->render_targets[i] = NULL;
7278 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7279 This->stencilBufferTarget = NULL;
7285 case WINED3DRTYPE_TEXTURE:
7286 case WINED3DRTYPE_CUBETEXTURE:
7287 case WINED3DRTYPE_VOLUMETEXTURE:
7288 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7289 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7290 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7291 This->stateBlock->textures[counter] = NULL;
7293 if (This->updateStateBlock != This->stateBlock ){
7294 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7295 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7296 This->updateStateBlock->textures[counter] = NULL;
7301 case WINED3DRTYPE_VOLUME:
7302 /* TODO: nothing really? */
7304 case WINED3DRTYPE_VERTEXBUFFER:
7305 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7308 TRACE("Cleaning up stream pointers\n");
7310 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7311 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7312 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7314 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7315 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7316 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7317 This->updateStateBlock->streamSource[streamNumber] = 0;
7318 /* Set changed flag? */
7321 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) */
7322 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7323 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7324 This->stateBlock->streamSource[streamNumber] = 0;
7330 case WINED3DRTYPE_INDEXBUFFER:
7331 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7332 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7333 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7334 This->updateStateBlock->pIndexData = NULL;
7337 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7338 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7339 This->stateBlock->pIndexData = NULL;
7345 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7350 /* Remove the resource from the resourceStore */
7351 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7353 TRACE("Resource released\n");
7357 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7359 IWineD3DResourceImpl *resource, *cursor;
7361 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7363 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7364 TRACE("enumerating resource %p\n", resource);
7365 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7366 ret = pCallback((IWineD3DResource *) resource, pData);
7367 if(ret == S_FALSE) {
7368 TRACE("Canceling enumeration\n");
7375 /**********************************************************
7376 * IWineD3DDevice VTbl follows
7377 **********************************************************/
7379 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7381 /*** IUnknown methods ***/
7382 IWineD3DDeviceImpl_QueryInterface,
7383 IWineD3DDeviceImpl_AddRef,
7384 IWineD3DDeviceImpl_Release,
7385 /*** IWineD3DDevice methods ***/
7386 IWineD3DDeviceImpl_GetParent,
7387 /*** Creation methods**/
7388 IWineD3DDeviceImpl_CreateVertexBuffer,
7389 IWineD3DDeviceImpl_CreateIndexBuffer,
7390 IWineD3DDeviceImpl_CreateStateBlock,
7391 IWineD3DDeviceImpl_CreateSurface,
7392 IWineD3DDeviceImpl_CreateTexture,
7393 IWineD3DDeviceImpl_CreateVolumeTexture,
7394 IWineD3DDeviceImpl_CreateVolume,
7395 IWineD3DDeviceImpl_CreateCubeTexture,
7396 IWineD3DDeviceImpl_CreateQuery,
7397 IWineD3DDeviceImpl_CreateSwapChain,
7398 IWineD3DDeviceImpl_CreateVertexDeclaration,
7399 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7400 IWineD3DDeviceImpl_CreateVertexShader,
7401 IWineD3DDeviceImpl_CreatePixelShader,
7402 IWineD3DDeviceImpl_CreatePalette,
7403 /*** Odd functions **/
7404 IWineD3DDeviceImpl_Init3D,
7405 IWineD3DDeviceImpl_InitGDI,
7406 IWineD3DDeviceImpl_Uninit3D,
7407 IWineD3DDeviceImpl_UninitGDI,
7408 IWineD3DDeviceImpl_SetMultithreaded,
7409 IWineD3DDeviceImpl_EvictManagedResources,
7410 IWineD3DDeviceImpl_GetAvailableTextureMem,
7411 IWineD3DDeviceImpl_GetBackBuffer,
7412 IWineD3DDeviceImpl_GetCreationParameters,
7413 IWineD3DDeviceImpl_GetDeviceCaps,
7414 IWineD3DDeviceImpl_GetDirect3D,
7415 IWineD3DDeviceImpl_GetDisplayMode,
7416 IWineD3DDeviceImpl_SetDisplayMode,
7417 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7418 IWineD3DDeviceImpl_GetRasterStatus,
7419 IWineD3DDeviceImpl_GetSwapChain,
7420 IWineD3DDeviceImpl_Reset,
7421 IWineD3DDeviceImpl_SetDialogBoxMode,
7422 IWineD3DDeviceImpl_SetCursorProperties,
7423 IWineD3DDeviceImpl_SetCursorPosition,
7424 IWineD3DDeviceImpl_ShowCursor,
7425 IWineD3DDeviceImpl_TestCooperativeLevel,
7426 /*** Getters and setters **/
7427 IWineD3DDeviceImpl_SetClipPlane,
7428 IWineD3DDeviceImpl_GetClipPlane,
7429 IWineD3DDeviceImpl_SetClipStatus,
7430 IWineD3DDeviceImpl_GetClipStatus,
7431 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7432 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7433 IWineD3DDeviceImpl_SetDepthStencilSurface,
7434 IWineD3DDeviceImpl_GetDepthStencilSurface,
7435 IWineD3DDeviceImpl_SetGammaRamp,
7436 IWineD3DDeviceImpl_GetGammaRamp,
7437 IWineD3DDeviceImpl_SetIndices,
7438 IWineD3DDeviceImpl_GetIndices,
7439 IWineD3DDeviceImpl_SetBaseVertexIndex,
7440 IWineD3DDeviceImpl_GetBaseVertexIndex,
7441 IWineD3DDeviceImpl_SetLight,
7442 IWineD3DDeviceImpl_GetLight,
7443 IWineD3DDeviceImpl_SetLightEnable,
7444 IWineD3DDeviceImpl_GetLightEnable,
7445 IWineD3DDeviceImpl_SetMaterial,
7446 IWineD3DDeviceImpl_GetMaterial,
7447 IWineD3DDeviceImpl_SetNPatchMode,
7448 IWineD3DDeviceImpl_GetNPatchMode,
7449 IWineD3DDeviceImpl_SetPaletteEntries,
7450 IWineD3DDeviceImpl_GetPaletteEntries,
7451 IWineD3DDeviceImpl_SetPixelShader,
7452 IWineD3DDeviceImpl_GetPixelShader,
7453 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7454 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7455 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7456 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7457 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7458 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7459 IWineD3DDeviceImpl_SetRenderState,
7460 IWineD3DDeviceImpl_GetRenderState,
7461 IWineD3DDeviceImpl_SetRenderTarget,
7462 IWineD3DDeviceImpl_GetRenderTarget,
7463 IWineD3DDeviceImpl_SetFrontBackBuffers,
7464 IWineD3DDeviceImpl_SetSamplerState,
7465 IWineD3DDeviceImpl_GetSamplerState,
7466 IWineD3DDeviceImpl_SetScissorRect,
7467 IWineD3DDeviceImpl_GetScissorRect,
7468 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7469 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7470 IWineD3DDeviceImpl_SetStreamSource,
7471 IWineD3DDeviceImpl_GetStreamSource,
7472 IWineD3DDeviceImpl_SetStreamSourceFreq,
7473 IWineD3DDeviceImpl_GetStreamSourceFreq,
7474 IWineD3DDeviceImpl_SetTexture,
7475 IWineD3DDeviceImpl_GetTexture,
7476 IWineD3DDeviceImpl_SetTextureStageState,
7477 IWineD3DDeviceImpl_GetTextureStageState,
7478 IWineD3DDeviceImpl_SetTransform,
7479 IWineD3DDeviceImpl_GetTransform,
7480 IWineD3DDeviceImpl_SetVertexDeclaration,
7481 IWineD3DDeviceImpl_GetVertexDeclaration,
7482 IWineD3DDeviceImpl_SetVertexShader,
7483 IWineD3DDeviceImpl_GetVertexShader,
7484 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7485 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7486 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7487 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7488 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7489 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7490 IWineD3DDeviceImpl_SetViewport,
7491 IWineD3DDeviceImpl_GetViewport,
7492 IWineD3DDeviceImpl_MultiplyTransform,
7493 IWineD3DDeviceImpl_ValidateDevice,
7494 IWineD3DDeviceImpl_ProcessVertices,
7495 /*** State block ***/
7496 IWineD3DDeviceImpl_BeginStateBlock,
7497 IWineD3DDeviceImpl_EndStateBlock,
7498 /*** Scene management ***/
7499 IWineD3DDeviceImpl_BeginScene,
7500 IWineD3DDeviceImpl_EndScene,
7501 IWineD3DDeviceImpl_Present,
7502 IWineD3DDeviceImpl_Clear,
7504 IWineD3DDeviceImpl_DrawPrimitive,
7505 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7506 IWineD3DDeviceImpl_DrawPrimitiveUP,
7507 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7508 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7509 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7510 IWineD3DDeviceImpl_DrawRectPatch,
7511 IWineD3DDeviceImpl_DrawTriPatch,
7512 IWineD3DDeviceImpl_DeletePatch,
7513 IWineD3DDeviceImpl_ColorFill,
7514 IWineD3DDeviceImpl_UpdateTexture,
7515 IWineD3DDeviceImpl_UpdateSurface,
7516 IWineD3DDeviceImpl_GetFrontBufferData,
7517 /*** object tracking ***/
7518 IWineD3DDeviceImpl_ResourceReleased,
7519 IWineD3DDeviceImpl_EnumResources
7522 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7523 WINED3DRS_ALPHABLENDENABLE ,
7524 WINED3DRS_ALPHAFUNC ,
7525 WINED3DRS_ALPHAREF ,
7526 WINED3DRS_ALPHATESTENABLE ,
7528 WINED3DRS_COLORWRITEENABLE ,
7529 WINED3DRS_DESTBLEND ,
7530 WINED3DRS_DITHERENABLE ,
7531 WINED3DRS_FILLMODE ,
7532 WINED3DRS_FOGDENSITY ,
7534 WINED3DRS_FOGSTART ,
7535 WINED3DRS_LASTPIXEL ,
7536 WINED3DRS_SHADEMODE ,
7537 WINED3DRS_SRCBLEND ,
7538 WINED3DRS_STENCILENABLE ,
7539 WINED3DRS_STENCILFAIL ,
7540 WINED3DRS_STENCILFUNC ,
7541 WINED3DRS_STENCILMASK ,
7542 WINED3DRS_STENCILPASS ,
7543 WINED3DRS_STENCILREF ,
7544 WINED3DRS_STENCILWRITEMASK ,
7545 WINED3DRS_STENCILZFAIL ,
7546 WINED3DRS_TEXTUREFACTOR ,
7557 WINED3DRS_ZWRITEENABLE
7560 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7561 WINED3DTSS_ALPHAARG0 ,
7562 WINED3DTSS_ALPHAARG1 ,
7563 WINED3DTSS_ALPHAARG2 ,
7564 WINED3DTSS_ALPHAOP ,
7565 WINED3DTSS_BUMPENVLOFFSET ,
7566 WINED3DTSS_BUMPENVLSCALE ,
7567 WINED3DTSS_BUMPENVMAT00 ,
7568 WINED3DTSS_BUMPENVMAT01 ,
7569 WINED3DTSS_BUMPENVMAT10 ,
7570 WINED3DTSS_BUMPENVMAT11 ,
7571 WINED3DTSS_COLORARG0 ,
7572 WINED3DTSS_COLORARG1 ,
7573 WINED3DTSS_COLORARG2 ,
7574 WINED3DTSS_COLOROP ,
7575 WINED3DTSS_RESULTARG ,
7576 WINED3DTSS_TEXCOORDINDEX ,
7577 WINED3DTSS_TEXTURETRANSFORMFLAGS
7580 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7581 WINED3DSAMP_ADDRESSU ,
7582 WINED3DSAMP_ADDRESSV ,
7583 WINED3DSAMP_ADDRESSW ,
7584 WINED3DSAMP_BORDERCOLOR ,
7585 WINED3DSAMP_MAGFILTER ,
7586 WINED3DSAMP_MINFILTER ,
7587 WINED3DSAMP_MIPFILTER ,
7588 WINED3DSAMP_MIPMAPLODBIAS ,
7589 WINED3DSAMP_MAXMIPLEVEL ,
7590 WINED3DSAMP_MAXANISOTROPY ,
7591 WINED3DSAMP_SRGBTEXTURE ,
7592 WINED3DSAMP_ELEMENTINDEX
7595 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7597 WINED3DRS_AMBIENTMATERIALSOURCE ,
7598 WINED3DRS_CLIPPING ,
7599 WINED3DRS_CLIPPLANEENABLE ,
7600 WINED3DRS_COLORVERTEX ,
7601 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7602 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7603 WINED3DRS_FOGDENSITY ,
7605 WINED3DRS_FOGSTART ,
7606 WINED3DRS_FOGTABLEMODE ,
7607 WINED3DRS_FOGVERTEXMODE ,
7608 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7609 WINED3DRS_LIGHTING ,
7610 WINED3DRS_LOCALVIEWER ,
7611 WINED3DRS_MULTISAMPLEANTIALIAS ,
7612 WINED3DRS_MULTISAMPLEMASK ,
7613 WINED3DRS_NORMALIZENORMALS ,
7614 WINED3DRS_PATCHEDGESTYLE ,
7615 WINED3DRS_POINTSCALE_A ,
7616 WINED3DRS_POINTSCALE_B ,
7617 WINED3DRS_POINTSCALE_C ,
7618 WINED3DRS_POINTSCALEENABLE ,
7619 WINED3DRS_POINTSIZE ,
7620 WINED3DRS_POINTSIZE_MAX ,
7621 WINED3DRS_POINTSIZE_MIN ,
7622 WINED3DRS_POINTSPRITEENABLE ,
7623 WINED3DRS_RANGEFOGENABLE ,
7624 WINED3DRS_SPECULARMATERIALSOURCE ,
7625 WINED3DRS_TWEENFACTOR ,
7626 WINED3DRS_VERTEXBLEND ,
7627 WINED3DRS_CULLMODE ,
7631 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7632 WINED3DTSS_TEXCOORDINDEX ,
7633 WINED3DTSS_TEXTURETRANSFORMFLAGS
7636 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7637 WINED3DSAMP_DMAPOFFSET
7640 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7641 DWORD rep = This->StateTable[state].representative;
7645 WineD3DContext *context;
7648 for(i = 0; i < This->numContexts; i++) {
7649 context = This->contexts[i];
7650 if(isStateDirty(context, rep)) continue;
7652 context->dirtyArray[context->numDirtyEntries++] = rep;
7655 context->isStateDirty[idx] |= (1 << shift);
7659 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7660 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7661 /* The drawable size of a pbuffer render target is the current pbuffer size
7663 *width = dev->pbufferWidth;
7664 *height = dev->pbufferHeight;
7667 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7668 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7670 *width = This->pow2Width;
7671 *height = This->pow2Height;
7674 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7675 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7676 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7677 * current context's drawable, which is the size of the back buffer of the swapchain
7678 * the active context belongs to. The back buffer of the swapchain is stored as the
7679 * surface the context belongs to.
7681 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7682 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;