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; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 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 /* Special case - Used during initialization to produce a placeholder stateblock
344 so other functions called can update a state block */
345 if (Type == WINED3DSBT_INIT) {
346 /* Don't bother increasing the reference count otherwise a device will never
347 be freed due to circular dependencies */
351 temp_result = allocate_shader_constants(object);
352 if (WINED3D_OK != temp_result)
355 /* Otherwise, might as well set the whole state block to the appropriate values */
356 if (This->stateBlock != NULL)
357 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
359 memset(object->streamFreq, 1, sizeof(object->streamFreq));
361 /* Reset the ref and type after kludging it */
362 object->wineD3DDevice = This;
364 object->blockType = Type;
366 TRACE("Updating changed flags appropriate for type %d\n", Type);
368 if (Type == WINED3DSBT_ALL) {
370 TRACE("ALL => Pretend everything has changed\n");
371 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
373 /* Lights are not part of the changed / set structure */
374 for(j = 0; j < LIGHTMAP_SIZE; j++) {
376 LIST_FOR_EACH(e, &object->lightMap[j]) {
377 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
378 light->changed = TRUE;
379 light->enabledChanged = TRUE;
382 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
383 object->contained_render_states[j - 1] = j;
385 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
386 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
387 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
388 object->contained_transform_states[j - 1] = j;
390 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
391 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
392 object->contained_vs_consts_f[j] = j;
394 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
395 for(j = 0; j < MAX_CONST_I; j++) {
396 object->contained_vs_consts_i[j] = j;
398 object->num_contained_vs_consts_i = MAX_CONST_I;
399 for(j = 0; j < MAX_CONST_B; j++) {
400 object->contained_vs_consts_b[j] = j;
402 object->num_contained_vs_consts_b = MAX_CONST_B;
403 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
404 object->contained_ps_consts_f[j] = j;
406 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
407 for(j = 0; j < MAX_CONST_I; j++) {
408 object->contained_ps_consts_i[j] = j;
410 object->num_contained_ps_consts_i = MAX_CONST_I;
411 for(j = 0; j < MAX_CONST_B; j++) {
412 object->contained_ps_consts_b[j] = j;
414 object->num_contained_ps_consts_b = MAX_CONST_B;
415 for(i = 0; i < MAX_TEXTURES; i++) {
416 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
417 object->contained_tss_states[object->num_contained_tss_states].stage = i;
418 object->contained_tss_states[object->num_contained_tss_states].state = j;
419 object->num_contained_tss_states++;
422 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
423 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
424 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
425 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
426 object->num_contained_sampler_states++;
430 for(i = 0; i < MAX_STREAMS; i++) {
431 if(object->streamSource[i]) {
432 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
435 if(object->pIndexData) {
436 IWineD3DIndexBuffer_AddRef(object->pIndexData);
438 if(object->vertexShader) {
439 IWineD3DVertexShader_AddRef(object->vertexShader);
441 if(object->pixelShader) {
442 IWineD3DPixelShader_AddRef(object->pixelShader);
445 } else if (Type == WINED3DSBT_PIXELSTATE) {
447 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
448 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
450 object->changed.pixelShader = TRUE;
452 /* Pixel Shader Constants */
453 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
454 object->contained_ps_consts_f[i] = i;
455 object->changed.pixelShaderConstantsF[i] = TRUE;
457 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
458 for (i = 0; i < MAX_CONST_B; ++i) {
459 object->contained_ps_consts_b[i] = i;
460 object->changed.pixelShaderConstantsB |= (1 << i);
462 object->num_contained_ps_consts_b = MAX_CONST_B;
463 for (i = 0; i < MAX_CONST_I; ++i) {
464 object->contained_ps_consts_i[i] = i;
465 object->changed.pixelShaderConstantsI |= (1 << i);
467 object->num_contained_ps_consts_i = MAX_CONST_I;
469 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
470 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
471 object->contained_render_states[i] = SavedPixelStates_R[i];
473 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
474 for (j = 0; j < MAX_TEXTURES; j++) {
475 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
476 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
477 object->contained_tss_states[object->num_contained_tss_states].stage = j;
478 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
479 object->num_contained_tss_states++;
482 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
483 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
484 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
485 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
486 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
487 object->num_contained_sampler_states++;
490 if(object->pixelShader) {
491 IWineD3DPixelShader_AddRef(object->pixelShader);
494 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
495 * on them. This makes releasing the buffer easier
497 for(i = 0; i < MAX_STREAMS; i++) {
498 object->streamSource[i] = NULL;
500 object->pIndexData = NULL;
501 object->vertexShader = NULL;
503 } else if (Type == WINED3DSBT_VERTEXSTATE) {
505 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
506 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
508 object->changed.vertexShader = TRUE;
510 /* Vertex Shader Constants */
511 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
512 object->changed.vertexShaderConstantsF[i] = TRUE;
513 object->contained_vs_consts_f[i] = i;
515 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
516 for (i = 0; i < MAX_CONST_B; ++i) {
517 object->contained_vs_consts_b[i] = i;
518 object->changed.vertexShaderConstantsB |= (1 << i);
520 object->num_contained_vs_consts_b = MAX_CONST_B;
521 for (i = 0; i < MAX_CONST_I; ++i) {
522 object->contained_vs_consts_i[i] = i;
523 object->changed.vertexShaderConstantsI |= (1 << i);
525 object->num_contained_vs_consts_i = MAX_CONST_I;
526 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
527 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
528 object->contained_render_states[i] = SavedVertexStates_R[i];
530 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
531 for (j = 0; j < MAX_TEXTURES; j++) {
532 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
533 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
534 object->contained_tss_states[object->num_contained_tss_states].stage = j;
535 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
536 object->num_contained_tss_states++;
539 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
540 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
541 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
542 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
543 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
544 object->num_contained_sampler_states++;
548 for(j = 0; j < LIGHTMAP_SIZE; j++) {
550 LIST_FOR_EACH(e, &object->lightMap[j]) {
551 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
552 light->changed = TRUE;
553 light->enabledChanged = TRUE;
557 for(i = 0; i < MAX_STREAMS; i++) {
558 if(object->streamSource[i]) {
559 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
562 if(object->vertexShader) {
563 IWineD3DVertexShader_AddRef(object->vertexShader);
565 object->pIndexData = NULL;
566 object->pixelShader = NULL;
568 FIXME("Unrecognized state block type %d\n", Type);
571 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
575 /* ************************************
577 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
580 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
582 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.
584 ******************************** */
586 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) {
587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
588 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
589 unsigned int Size = 1;
590 const struct GlPixelFormatDesc *glDesc;
591 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
593 TRACE("(%p) Create surface\n",This);
595 /** FIXME: Check ranges on the inputs are valid
598 * [in] Quality level. The valid range is between zero and one less than the level
599 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
600 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
601 * values of paired render targets, depth stencil surfaces, and the MultiSample type
603 *******************************/
608 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
610 * If this flag is set, the contents of the depth stencil buffer will be
611 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
612 * with a different depth surface.
614 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
615 ***************************/
617 if(MultisampleQuality > 0) {
618 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
619 MultisampleQuality=0;
622 /** FIXME: Check that the format is supported
624 *******************************/
626 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
627 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
629 *********************************/
630 mul_4w = (Width + 3) & ~3;
631 mul_4h = (Height + 3) & ~3;
632 if (WINED3DFMT_UNKNOWN == Format) {
634 } else if (Format == WINED3DFMT_DXT1) {
635 /* DXT1 is half byte per pixel */
636 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
638 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
639 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
640 Format == WINED3DFMT_ATI2N) {
641 Size = (mul_4w * tableEntry->bpp * mul_4h);
643 /* The pitch is a multiple of 4 bytes */
644 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
648 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
650 /** Create and initialise the surface resource **/
651 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
652 /* "Standalone" surface */
653 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
655 object->currentDesc.Width = Width;
656 object->currentDesc.Height = Height;
657 object->currentDesc.MultiSampleType = MultiSample;
658 object->currentDesc.MultiSampleQuality = MultisampleQuality;
659 object->glDescription.level = Level;
660 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
661 list_init(&object->overlays);
664 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
665 object->Flags |= Discard ? SFLAG_DISCARD : 0;
666 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
667 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
670 if (WINED3DFMT_UNKNOWN != Format) {
671 object->bytesPerPixel = tableEntry->bpp;
673 object->bytesPerPixel = 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
685 case WINED3DPOOL_SCRATCH:
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
691 case WINED3DPOOL_SYSTEMMEM:
692 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED:
695 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
699 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
701 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 FIXME("(%p) Unknown pool %d\n", This, Pool);
709 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This, Width, Height, Format, debug_d3dformat(Format),
717 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
719 /* Look at the implementation and set the correct Vtable */
722 /* Check if a 3D adapter is available when creating gl surfaces */
724 ERR("OpenGL surfaces are not available without opengl\n");
725 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
726 HeapFree(GetProcessHeap(), 0, object);
727 return WINED3DERR_NOTAVAILABLE;
732 object->lpVtbl = &IWineGDISurface_Vtbl;
736 /* To be sure to catch this */
737 ERR("Unknown requested surface implementation %d!\n", Impl);
738 IWineD3DSurface_Release((IWineD3DSurface *) object);
739 return WINED3DERR_INVALIDCALL;
742 list_init(&object->renderbuffers);
744 /* Call the private setup routine */
745 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
749 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
750 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
751 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
752 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
755 IWineD3DTextureImpl *object;
760 unsigned int pow2Width;
761 unsigned int pow2Height;
762 const struct GlPixelFormatDesc *glDesc;
763 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
765 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
766 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
767 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
769 /* TODO: It should only be possible to create textures for formats
770 that are reported as supported */
771 if (WINED3DFMT_UNKNOWN >= Format) {
772 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
773 return WINED3DERR_INVALIDCALL;
776 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
777 D3DINITIALIZEBASETEXTURE(object->baseTexture);
778 object->width = Width;
779 object->height = Height;
781 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
782 object->baseTexture.minMipLookup = minMipLookup;
783 object->baseTexture.magLookup = magLookup;
785 object->baseTexture.minMipLookup = minMipLookup_noFilter;
786 object->baseTexture.magLookup = magLookup_noFilter;
789 /** Non-power2 support **/
790 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
794 /* Find the nearest pow2 match */
795 pow2Width = pow2Height = 1;
796 while (pow2Width < Width) pow2Width <<= 1;
797 while (pow2Height < Height) pow2Height <<= 1;
799 if(pow2Width != Width || pow2Height != Height) {
801 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
802 HeapFree(GetProcessHeap(), 0, object);
804 return WINED3DERR_INVALIDCALL;
811 /** FIXME: add support for real non-power-two if it's provided by the video card **/
812 /* Precalculated scaling for 'faked' non power of two texture coords.
813 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
814 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
815 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
817 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
818 object->baseTexture.pow2Matrix[0] = 1.0;
819 object->baseTexture.pow2Matrix[5] = 1.0;
820 object->baseTexture.pow2Matrix[10] = 1.0;
821 object->baseTexture.pow2Matrix[15] = 1.0;
822 object->target = GL_TEXTURE_2D;
823 object->cond_np2 = TRUE;
824 object->baseTexture.minMipLookup = minMipLookup_noFilter;
825 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
826 (Width != pow2Width || Height != pow2Height) &&
827 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
829 object->baseTexture.pow2Matrix[0] = (float)Width;
830 object->baseTexture.pow2Matrix[5] = (float)Height;
831 object->baseTexture.pow2Matrix[10] = 1.0;
832 object->baseTexture.pow2Matrix[15] = 1.0;
833 object->target = GL_TEXTURE_RECTANGLE_ARB;
834 object->cond_np2 = TRUE;
835 object->baseTexture.minMipLookup = minMipLookup_noFilter;
837 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
838 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
839 object->baseTexture.pow2Matrix[10] = 1.0;
840 object->baseTexture.pow2Matrix[15] = 1.0;
841 object->target = GL_TEXTURE_2D;
842 object->cond_np2 = FALSE;
844 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
846 /* Calculate levels for mip mapping */
847 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
848 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
849 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
850 return WINED3DERR_INVALIDCALL;
853 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL;
856 object->baseTexture.levels = 1;
857 } else if (Levels == 0) {
858 object->baseTexture.levels = wined3d_log2i(max(Width, Height)) + 1;
859 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
862 /* Generate all the surfaces */
865 for (i = 0; i < object->baseTexture.levels; i++)
867 /* use the callback to create the texture surface */
868 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
869 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
870 FIXME("Failed to create surface %p\n", object);
872 object->surfaces[i] = NULL;
873 IWineD3DTexture_Release((IWineD3DTexture *)object);
879 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
880 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
881 surface_set_texture_target(object->surfaces[i], object->target);
882 /* calculate the next mipmap level */
883 tmpW = max(1, tmpW >> 1);
884 tmpH = max(1, tmpH >> 1);
886 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
888 TRACE("(%p) : Created texture %p\n", This, object);
892 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
893 UINT Width, UINT Height, UINT Depth,
894 UINT Levels, DWORD Usage,
895 WINED3DFORMAT Format, WINED3DPOOL Pool,
896 IWineD3DVolumeTexture **ppVolumeTexture,
897 HANDLE *pSharedHandle, IUnknown *parent,
898 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
900 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
901 IWineD3DVolumeTextureImpl *object;
906 const struct GlPixelFormatDesc *glDesc;
908 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
910 /* TODO: It should only be possible to create textures for formats
911 that are reported as supported */
912 if (WINED3DFMT_UNKNOWN >= Format) {
913 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
914 return WINED3DERR_INVALIDCALL;
916 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
917 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
918 return WINED3DERR_INVALIDCALL;
921 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
922 D3DINITIALIZEBASETEXTURE(object->baseTexture);
924 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
925 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
927 /* Is NP2 support for volumes needed? */
928 object->baseTexture.pow2Matrix[ 0] = 1.0;
929 object->baseTexture.pow2Matrix[ 5] = 1.0;
930 object->baseTexture.pow2Matrix[10] = 1.0;
931 object->baseTexture.pow2Matrix[15] = 1.0;
933 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
934 object->baseTexture.minMipLookup = minMipLookup;
935 object->baseTexture.magLookup = magLookup;
937 object->baseTexture.minMipLookup = minMipLookup_noFilter;
938 object->baseTexture.magLookup = magLookup_noFilter;
941 /* Calculate levels for mip mapping */
942 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
943 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
944 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
945 return WINED3DERR_INVALIDCALL;
948 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
949 return WINED3DERR_INVALIDCALL;
951 object->baseTexture.levels = 1;
952 } else if (Levels == 0) {
953 object->baseTexture.levels = wined3d_log2i(max(max(Width, Height), Depth)) + 1;
954 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
957 /* Generate all the surfaces */
962 for (i = 0; i < object->baseTexture.levels; i++)
965 /* Create the volume */
966 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
967 &object->volumes[i], pSharedHandle);
970 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
971 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
972 *ppVolumeTexture = NULL;
976 /* Set its container to this object */
977 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
979 /* calculate the next mipmap level */
980 tmpW = max(1, tmpW >> 1);
981 tmpH = max(1, tmpH >> 1);
982 tmpD = max(1, tmpD >> 1);
984 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
986 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
987 TRACE("(%p) : Created volume texture %p\n", This, object);
991 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
992 UINT Width, UINT Height, UINT Depth,
994 WINED3DFORMAT Format, WINED3DPOOL Pool,
995 IWineD3DVolume** ppVolume,
996 HANDLE* pSharedHandle, IUnknown *parent) {
998 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
999 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1000 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1002 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1003 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1004 return WINED3DERR_INVALIDCALL;
1007 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1009 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1010 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1012 object->currentDesc.Width = Width;
1013 object->currentDesc.Height = Height;
1014 object->currentDesc.Depth = Depth;
1015 object->bytesPerPixel = formatDesc->bpp;
1017 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1018 object->lockable = TRUE;
1019 object->locked = FALSE;
1020 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1021 object->dirty = TRUE;
1023 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1026 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1027 UINT Levels, DWORD Usage,
1028 WINED3DFORMAT Format, WINED3DPOOL Pool,
1029 IWineD3DCubeTexture **ppCubeTexture,
1030 HANDLE *pSharedHandle, IUnknown *parent,
1031 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1033 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1034 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1038 unsigned int pow2EdgeLength;
1039 const struct GlPixelFormatDesc *glDesc;
1040 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1042 /* TODO: It should only be possible to create textures for formats
1043 that are reported as supported */
1044 if (WINED3DFMT_UNKNOWN >= Format) {
1045 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1046 return WINED3DERR_INVALIDCALL;
1049 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1050 WARN("(%p) : Tried to create not supported cube texture\n", This);
1051 return WINED3DERR_INVALIDCALL;
1054 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1055 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1057 TRACE("(%p) Create Cube Texture\n", This);
1059 /* Find the nearest pow2 match */
1061 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1063 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
1064 /* Precalculated scaling for 'faked' non power of two texture coords */
1065 object->baseTexture.pow2Matrix[ 0] = 1.0;
1066 object->baseTexture.pow2Matrix[ 5] = 1.0;
1067 object->baseTexture.pow2Matrix[10] = 1.0;
1068 object->baseTexture.pow2Matrix[15] = 1.0;
1070 /* Precalculated scaling for 'faked' non power of two texture coords */
1071 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1072 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1073 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1074 object->baseTexture.pow2Matrix[15] = 1.0;
1077 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1078 object->baseTexture.minMipLookup = minMipLookup;
1079 object->baseTexture.magLookup = magLookup;
1081 object->baseTexture.minMipLookup = minMipLookup_noFilter;
1082 object->baseTexture.magLookup = magLookup_noFilter;
1085 /* Calculate levels for mip mapping */
1086 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1087 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1088 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1089 HeapFree(GetProcessHeap(), 0, object);
1090 *ppCubeTexture = NULL;
1092 return WINED3DERR_INVALIDCALL;
1095 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1096 HeapFree(GetProcessHeap(), 0, object);
1097 *ppCubeTexture = NULL;
1099 return WINED3DERR_INVALIDCALL;
1101 object->baseTexture.levels = 1;
1102 } else if (Levels == 0) {
1103 object->baseTexture.levels = wined3d_log2i(EdgeLength) + 1;
1104 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1107 /* Generate all the surfaces */
1109 for (i = 0; i < object->baseTexture.levels; i++) {
1111 /* Create the 6 faces */
1112 for (j = 0; j < 6; j++) {
1113 static const GLenum cube_targets[6] = {
1114 GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
1115 GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
1116 GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
1117 GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
1118 GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
1119 GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB
1122 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1123 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1125 if(hr!= WINED3D_OK) {
1129 for (l = 0; l < j; l++) {
1130 IWineD3DSurface_Release(object->surfaces[l][i]);
1132 for (k = 0; k < i; k++) {
1133 for (l = 0; l < 6; l++) {
1134 IWineD3DSurface_Release(object->surfaces[l][k]);
1138 FIXME("(%p) Failed to create surface\n",object);
1139 HeapFree(GetProcessHeap(),0,object);
1140 *ppCubeTexture = NULL;
1143 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1144 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1145 surface_set_texture_target(object->surfaces[j][i], cube_targets[j]);
1147 tmpW = max(1, tmpW >> 1);
1149 object->baseTexture.shader_color_fixup = glDesc->color_fixup;
1151 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1152 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1156 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1158 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1159 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1160 const IWineD3DQueryVtbl *vtable;
1162 /* Just a check to see if we support this type of query */
1164 case WINED3DQUERYTYPE_OCCLUSION:
1165 TRACE("(%p) occlusion query\n", This);
1166 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1169 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1171 vtable = &IWineD3DOcclusionQuery_Vtbl;
1174 case WINED3DQUERYTYPE_EVENT:
1175 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1176 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1177 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1179 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1181 vtable = &IWineD3DEventQuery_Vtbl;
1185 case WINED3DQUERYTYPE_VCACHE:
1186 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1187 case WINED3DQUERYTYPE_VERTEXSTATS:
1188 case WINED3DQUERYTYPE_TIMESTAMP:
1189 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1190 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1191 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1192 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1193 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1194 case WINED3DQUERYTYPE_PIXELTIMINGS:
1195 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1196 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1198 /* Use the base Query vtable until we have a special one for each query */
1199 vtable = &IWineD3DQuery_Vtbl;
1200 FIXME("(%p) Unhandled query type %d\n", This, Type);
1202 if(NULL == ppQuery || hr != WINED3D_OK) {
1206 D3DCREATEOBJECTINSTANCE(object, Query)
1207 object->lpVtbl = vtable;
1208 object->type = Type;
1209 object->state = QUERY_CREATED;
1210 /* allocated the 'extended' data based on the type of query requested */
1212 case WINED3DQUERYTYPE_OCCLUSION:
1213 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1214 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1216 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1217 TRACE("(%p) Allocating data for an occlusion query\n", This);
1219 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1221 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1225 case WINED3DQUERYTYPE_EVENT:
1226 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1227 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1229 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
1231 if(GL_SUPPORT(APPLE_FENCE)) {
1232 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1233 checkGLcall("glGenFencesAPPLE");
1234 } else if(GL_SUPPORT(NV_FENCE)) {
1235 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1236 checkGLcall("glGenFencesNV");
1241 case WINED3DQUERYTYPE_VCACHE:
1242 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1243 case WINED3DQUERYTYPE_VERTEXSTATS:
1244 case WINED3DQUERYTYPE_TIMESTAMP:
1245 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1246 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1247 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1248 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1249 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1250 case WINED3DQUERYTYPE_PIXELTIMINGS:
1251 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1252 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1254 object->extendedData = 0;
1255 FIXME("(%p) Unhandled query type %d\n",This , Type);
1257 TRACE("(%p) : Created Query %p\n", This, object);
1261 /*****************************************************************************
1262 * IWineD3DDeviceImpl_SetupFullscreenWindow
1264 * Helper function that modifies a HWND's Style and ExStyle for proper
1268 * iface: Pointer to the IWineD3DDevice interface
1269 * window: Window to setup
1271 *****************************************************************************/
1272 static LONG fullscreen_style(LONG orig_style) {
1273 LONG style = orig_style;
1274 style &= ~WS_CAPTION;
1275 style &= ~WS_THICKFRAME;
1277 /* Make sure the window is managed, otherwise we won't get keyboard input */
1278 style |= WS_POPUP | WS_SYSMENU;
1283 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1284 LONG exStyle = orig_exStyle;
1286 /* Filter out window decorations */
1287 exStyle &= ~WS_EX_WINDOWEDGE;
1288 exStyle &= ~WS_EX_CLIENTEDGE;
1293 static void IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1296 LONG style, exStyle;
1297 /* Don't do anything if an original style is stored.
1298 * That shouldn't happen
1300 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1301 if (This->style || This->exStyle) {
1302 ERR("(%p): Want to change the window parameters of HWND %p, but "
1303 "another style is stored for restoration afterwards\n", This, window);
1306 /* Get the parameters and save them */
1307 style = GetWindowLongW(window, GWL_STYLE);
1308 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1309 This->style = style;
1310 This->exStyle = exStyle;
1312 style = fullscreen_style(style);
1313 exStyle = fullscreen_exStyle(exStyle);
1315 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1316 This->style, This->exStyle, style, exStyle);
1318 SetWindowLongW(window, GWL_STYLE, style);
1319 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1321 /* Inform the window about the update. */
1322 SetWindowPos(window, HWND_TOP, 0, 0,
1323 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1326 /*****************************************************************************
1327 * IWineD3DDeviceImpl_RestoreWindow
1329 * Helper function that restores a windows' properties when taking it out
1330 * of fullscreen mode
1333 * iface: Pointer to the IWineD3DDevice interface
1334 * window: Window to setup
1336 *****************************************************************************/
1337 static void IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1338 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1339 LONG style, exStyle;
1341 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1342 * switch, do nothing
1344 if (!This->style && !This->exStyle) return;
1346 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1347 This, window, This->style, This->exStyle);
1349 style = GetWindowLongW(window, GWL_STYLE);
1350 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1352 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1353 * Some applications change it before calling Reset() when switching between windowed and
1354 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1356 if(style == fullscreen_style(This->style) &&
1357 exStyle == fullscreen_style(This->exStyle)) {
1358 SetWindowLongW(window, GWL_STYLE, This->style);
1359 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1362 /* Delete the old values */
1366 /* Inform the window about the update */
1367 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1368 0, 0, 0, 0, /* Pos, Size, ignored */
1369 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1372 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1373 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSwapChain(IWineD3DDevice* iface,
1374 WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1375 IUnknown* parent, D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1376 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil, WINED3DSURFTYPE surface_type)
1378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1381 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1383 IUnknown *bufferParent;
1384 BOOL displaymode_set = FALSE;
1385 WINED3DDISPLAYMODE Mode;
1386 const StaticPixelFormatDesc *formatDesc;
1388 TRACE("(%p) : Created Additional Swap Chain\n", This);
1390 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1391 * does a device hold a reference to a swap chain giving them a lifetime of the device
1392 * or does the swap chain notify the device of its destruction.
1393 *******************************/
1395 /* Check the params */
1396 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1397 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1398 return WINED3DERR_INVALIDCALL;
1399 } else if (pPresentationParameters->BackBufferCount > 1) {
1400 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1403 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1404 switch(surface_type) {
1406 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1408 case SURFACE_OPENGL:
1409 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1411 case SURFACE_UNKNOWN:
1412 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1413 return WINED3DERR_INVALIDCALL;
1416 /*********************
1417 * Lookup the window Handle and the relating X window handle
1418 ********************/
1420 /* Setup hwnd we are using, plus which display this equates to */
1421 object->win_handle = pPresentationParameters->hDeviceWindow;
1422 if (!object->win_handle) {
1423 object->win_handle = This->createParms.hFocusWindow;
1425 if(!pPresentationParameters->Windowed && object->win_handle) {
1426 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1427 pPresentationParameters->BackBufferWidth,
1428 pPresentationParameters->BackBufferHeight);
1431 hDc = GetDC(object->win_handle);
1432 TRACE("Using hDc %p\n", hDc);
1435 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1436 return WINED3DERR_NOTAVAILABLE;
1439 /* Get info on the current display setup */
1440 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1441 object->orig_width = Mode.Width;
1442 object->orig_height = Mode.Height;
1443 object->orig_fmt = Mode.Format;
1444 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1446 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1447 * then the corresponding dimension of the client area of the hDeviceWindow
1448 * (or the focus window, if hDeviceWindow is NULL) is taken.
1449 **********************/
1451 if (pPresentationParameters->Windowed &&
1452 ((pPresentationParameters->BackBufferWidth == 0) ||
1453 (pPresentationParameters->BackBufferHeight == 0) ||
1454 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1457 GetClientRect(object->win_handle, &Rect);
1459 if (pPresentationParameters->BackBufferWidth == 0) {
1460 pPresentationParameters->BackBufferWidth = Rect.right;
1461 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1463 if (pPresentationParameters->BackBufferHeight == 0) {
1464 pPresentationParameters->BackBufferHeight = Rect.bottom;
1465 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1467 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1468 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1469 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1473 /* Put the correct figures in the presentation parameters */
1474 TRACE("Copying across presentation parameters\n");
1475 object->presentParms = *pPresentationParameters;
1477 TRACE("calling rendertarget CB\n");
1478 hr = D3DCB_CreateRenderTarget(This->parent,
1480 object->presentParms.BackBufferWidth,
1481 object->presentParms.BackBufferHeight,
1482 object->presentParms.BackBufferFormat,
1483 object->presentParms.MultiSampleType,
1484 object->presentParms.MultiSampleQuality,
1485 TRUE /* Lockable */,
1486 &object->frontBuffer,
1487 NULL /* pShared (always null)*/);
1488 if (SUCCEEDED(hr)) {
1489 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1490 if(surface_type == SURFACE_OPENGL) {
1491 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1494 ERR("Failed to create the front buffer\n");
1498 /*********************
1499 * Windowed / Fullscreen
1500 *******************/
1503 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1504 * so we should really check to see if there is a fullscreen swapchain already
1505 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1506 **************************************/
1508 if (!pPresentationParameters->Windowed) {
1509 WINED3DDISPLAYMODE mode;
1512 /* Change the display settings */
1513 mode.Width = pPresentationParameters->BackBufferWidth;
1514 mode.Height = pPresentationParameters->BackBufferHeight;
1515 mode.Format = pPresentationParameters->BackBufferFormat;
1516 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1518 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1519 displaymode_set = TRUE;
1523 * Create an opengl context for the display visual
1524 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1525 * use different properties after that point in time. FIXME: How to handle when requested format
1526 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1527 * it chooses is identical to the one already being used!
1528 **********************************/
1529 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1531 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1532 if(!object->context) {
1533 ERR("Failed to create the context array\n");
1537 object->num_contexts = 1;
1539 if(surface_type == SURFACE_OPENGL) {
1540 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1541 if (!object->context[0]) {
1542 ERR("Failed to create a new context\n");
1543 hr = WINED3DERR_NOTAVAILABLE;
1546 TRACE("Context created (HWND=%p, glContext=%p)\n",
1547 object->win_handle, object->context[0]->glCtx);
1551 /*********************
1552 * Create the back, front and stencil buffers
1553 *******************/
1554 if(object->presentParms.BackBufferCount > 0) {
1557 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1558 if(!object->backBuffer) {
1559 ERR("Out of memory\n");
1564 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1565 TRACE("calling rendertarget CB\n");
1566 hr = D3DCB_CreateRenderTarget(This->parent,
1568 object->presentParms.BackBufferWidth,
1569 object->presentParms.BackBufferHeight,
1570 object->presentParms.BackBufferFormat,
1571 object->presentParms.MultiSampleType,
1572 object->presentParms.MultiSampleQuality,
1573 TRUE /* Lockable */,
1574 &object->backBuffer[i],
1575 NULL /* pShared (always null)*/);
1577 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1579 ERR("Cannot create new back buffer\n");
1582 if(surface_type == SURFACE_OPENGL) {
1584 glDrawBuffer(GL_BACK);
1585 checkGLcall("glDrawBuffer(GL_BACK)");
1590 object->backBuffer = NULL;
1592 /* Single buffering - draw to front buffer */
1593 if(surface_type == SURFACE_OPENGL) {
1595 glDrawBuffer(GL_FRONT);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1601 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1602 if (pPresentationParameters->EnableAutoDepthStencil && surface_type == SURFACE_OPENGL) {
1603 TRACE("Creating depth stencil buffer\n");
1604 if (This->auto_depth_stencil_buffer == NULL ) {
1605 hr = D3DCB_CreateDepthStencil(This->parent,
1607 object->presentParms.BackBufferWidth,
1608 object->presentParms.BackBufferHeight,
1609 object->presentParms.AutoDepthStencilFormat,
1610 object->presentParms.MultiSampleType,
1611 object->presentParms.MultiSampleQuality,
1612 FALSE /* FIXME: Discard */,
1613 &This->auto_depth_stencil_buffer,
1614 NULL /* pShared (always null)*/ );
1615 if (SUCCEEDED(hr)) {
1616 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1618 ERR("Failed to create the auto depth stencil\n");
1624 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1626 TRACE("Created swapchain %p\n", object);
1627 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, pPresentationParameters->EnableAutoDepthStencil);
1631 if (displaymode_set) {
1635 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1638 /* Change the display settings */
1639 memset(&devmode, 0, sizeof(devmode));
1640 devmode.dmSize = sizeof(devmode);
1641 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1642 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1643 devmode.dmPelsWidth = object->orig_width;
1644 devmode.dmPelsHeight = object->orig_height;
1645 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1648 if (object->backBuffer) {
1650 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1651 if(object->backBuffer[i]) {
1652 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1653 IUnknown_Release(bufferParent); /* once for the get parent */
1654 if (IUnknown_Release(bufferParent) > 0) {
1655 FIXME("(%p) Something's still holding the back buffer\n",This);
1659 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1660 object->backBuffer = NULL;
1662 if(object->context && object->context[0])
1663 DestroyContext(This, object->context[0]);
1664 if(object->frontBuffer) {
1665 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1666 IUnknown_Release(bufferParent); /* once for the get parent */
1667 if (IUnknown_Release(bufferParent) > 0) {
1668 FIXME("(%p) Something's still holding the front buffer\n",This);
1671 HeapFree(GetProcessHeap(), 0, object);
1675 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1676 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1678 TRACE("(%p)\n", This);
1680 return This->NumberOfSwapChains;
1683 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1685 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1687 if(iSwapChain < This->NumberOfSwapChains) {
1688 *pSwapChain = This->swapchains[iSwapChain];
1689 IWineD3DSwapChain_AddRef(*pSwapChain);
1690 TRACE("(%p) returning %p\n", This, *pSwapChain);
1693 TRACE("Swapchain out of range\n");
1695 return WINED3DERR_INVALIDCALL;
1700 * Vertex Declaration
1702 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1703 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1705 IWineD3DVertexDeclarationImpl *object = NULL;
1706 HRESULT hr = WINED3D_OK;
1708 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1709 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1711 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1713 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1715 IWineD3DVertexDeclaration_Release((IWineD3DVertexDeclaration *)object);
1716 *ppVertexDeclaration = NULL;
1722 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1723 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1725 unsigned int idx, idx2;
1726 unsigned int offset;
1727 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1728 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1729 BOOL has_blend_idx = has_blend &&
1730 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1731 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1732 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1733 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1734 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1735 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1736 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1738 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1739 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1741 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1742 WINED3DVERTEXELEMENT *elements = NULL;
1745 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1746 if (has_blend_idx) num_blends--;
1748 /* Compute declaration size */
1749 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1750 has_psize + has_diffuse + has_specular + num_textures + 1;
1752 /* convert the declaration */
1753 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1757 elements[size-1] = end_element;
1760 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1761 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1762 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1765 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1766 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1768 elements[idx].UsageIndex = 0;
1771 if (has_blend && (num_blends > 0)) {
1772 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1773 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1775 switch(num_blends) {
1776 case 1: elements[idx].Type = WINED3DDECLTYPE_FLOAT1; break;
1777 case 2: elements[idx].Type = WINED3DDECLTYPE_FLOAT2; break;
1778 case 3: elements[idx].Type = WINED3DDECLTYPE_FLOAT3; break;
1779 case 4: elements[idx].Type = WINED3DDECLTYPE_FLOAT4; break;
1781 ERR("Unexpected amount of blend values: %u\n", num_blends);
1784 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1785 elements[idx].UsageIndex = 0;
1788 if (has_blend_idx) {
1789 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1790 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1791 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1792 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1793 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1795 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1796 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1797 elements[idx].UsageIndex = 0;
1801 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1802 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1803 elements[idx].UsageIndex = 0;
1807 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1808 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1809 elements[idx].UsageIndex = 0;
1813 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1814 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1815 elements[idx].UsageIndex = 0;
1819 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1820 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1821 elements[idx].UsageIndex = 1;
1824 for (idx2 = 0; idx2 < num_textures; idx2++) {
1825 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1826 switch (numcoords) {
1827 case WINED3DFVF_TEXTUREFORMAT1:
1828 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1830 case WINED3DFVF_TEXTUREFORMAT2:
1831 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1833 case WINED3DFVF_TEXTUREFORMAT3:
1834 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1836 case WINED3DFVF_TEXTUREFORMAT4:
1837 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1840 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1841 elements[idx].UsageIndex = idx2;
1845 /* Now compute offsets, and initialize the rest of the fields */
1846 for (idx = 0, offset = 0; idx < size-1; idx++) {
1847 elements[idx].Stream = 0;
1848 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1849 elements[idx].Offset = offset;
1850 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1853 *ppVertexElements = elements;
1857 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1858 WINED3DVERTEXELEMENT* elements = NULL;
1859 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1863 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1864 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1866 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1867 HeapFree(GetProcessHeap(), 0, elements);
1868 if (hr != S_OK) return hr;
1873 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1875 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1876 HRESULT hr = WINED3D_OK;
1877 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1878 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1880 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1882 if (vertex_declaration) {
1883 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1886 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1888 if (WINED3D_OK != hr) {
1889 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1890 IWineD3DVertexShader_Release(*ppVertexShader);
1891 return WINED3DERR_INVALIDCALL;
1893 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1898 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1899 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1900 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1901 HRESULT hr = WINED3D_OK;
1903 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1904 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1905 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1906 if (WINED3D_OK == hr) {
1907 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1908 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1910 WARN("(%p) : Failed to create pixel shader\n", This);
1916 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1917 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 IWineD3DPaletteImpl *object;
1922 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1924 /* Create the new object */
1925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1927 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1928 return E_OUTOFMEMORY;
1931 object->lpVtbl = &IWineD3DPalette_Vtbl;
1933 object->Flags = Flags;
1934 object->parent = Parent;
1935 object->wineD3DDevice = This;
1936 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1938 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1941 HeapFree( GetProcessHeap(), 0, object);
1942 return E_OUTOFMEMORY;
1945 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1947 IWineD3DPalette_Release((IWineD3DPalette *) object);
1951 *Palette = (IWineD3DPalette *) object;
1956 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1960 HDC dcb = NULL, dcs = NULL;
1961 WINEDDCOLORKEY colorkey;
1963 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1966 GetObjectA(hbm, sizeof(BITMAP), &bm);
1967 dcb = CreateCompatibleDC(NULL);
1969 SelectObject(dcb, hbm);
1973 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1974 * couldn't be loaded
1976 memset(&bm, 0, sizeof(bm));
1981 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1982 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1983 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1985 ERR("Wine logo requested, but failed to create surface\n");
1990 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1991 if(FAILED(hr)) goto out;
1992 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1993 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1995 colorkey.dwColorSpaceLowValue = 0;
1996 colorkey.dwColorSpaceHighValue = 0;
1997 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1999 /* Fill the surface with a white color to show that wined3d is there */
2000 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2013 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2015 /* Under DirectX you can have texture stage operations even if no texture is
2016 bound, whereas opengl will only do texture operations when a valid texture is
2017 bound. We emulate this by creating dummy textures and binding them to each
2018 texture stage, but disable all stages by default. Hence if a stage is enabled
2019 then the default texture will kick in until replaced by a SetTexture call */
2022 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2023 /* The dummy texture does not have client storage backing */
2024 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2025 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2027 for (i = 0; i < GL_LIMITS(textures); i++) {
2028 GLubyte white = 255;
2030 /* Make appropriate texture active */
2031 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2032 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2033 checkGLcall("glActiveTextureARB");
2035 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2038 /* Generate an opengl texture name */
2039 glGenTextures(1, &This->dummyTextureName[i]);
2040 checkGLcall("glGenTextures");
2041 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2043 /* Generate a dummy 2d texture (not using 1d because they cause many
2044 * DRI drivers fall back to sw) */
2045 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2046 checkGLcall("glBindTexture");
2048 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2049 checkGLcall("glTexImage2D");
2051 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2052 /* Reenable because if supported it is enabled by default */
2053 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2054 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2060 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2061 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2062 IWineD3DSwapChainImpl *swapchain = NULL;
2067 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2068 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2069 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2071 /* TODO: Test if OpenGL is compiled in and loaded */
2073 TRACE("(%p) : Creating stateblock\n", This);
2074 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2075 hr = IWineD3DDevice_CreateStateBlock(iface,
2077 (IWineD3DStateBlock **)&This->stateBlock,
2079 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2080 WARN("Failed to create stateblock\n");
2083 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2084 This->updateStateBlock = This->stateBlock;
2085 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2087 hr = allocate_shader_constants(This->updateStateBlock);
2088 if (WINED3D_OK != hr) {
2092 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2093 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2095 This->NumberOfPalettes = 1;
2096 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2097 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2098 ERR("Out of memory!\n");
2101 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2102 if(!This->palettes[0]) {
2103 ERR("Out of memory!\n");
2106 for (i = 0; i < 256; ++i) {
2107 This->palettes[0][i].peRed = 0xFF;
2108 This->palettes[0][i].peGreen = 0xFF;
2109 This->palettes[0][i].peBlue = 0xFF;
2110 This->palettes[0][i].peFlags = 0xFF;
2112 This->currentPalette = 0;
2114 /* Initialize the texture unit mapping to a 1:1 mapping */
2115 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2116 if (state < GL_LIMITS(fragment_samplers)) {
2117 This->texUnitMap[state] = state;
2118 This->rev_tex_unit_map[state] = state;
2120 This->texUnitMap[state] = -1;
2121 This->rev_tex_unit_map[state] = -1;
2125 /* Setup the implicit swapchain */
2126 TRACE("Creating implicit swapchain\n");
2127 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2128 if (FAILED(hr) || !swapchain) {
2129 WARN("Failed to create implicit swapchain\n");
2133 This->NumberOfSwapChains = 1;
2134 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2135 if(!This->swapchains) {
2136 ERR("Out of memory!\n");
2139 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2141 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2142 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2143 This->render_targets[0] = swapchain->backBuffer[0];
2144 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2147 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2148 This->render_targets[0] = swapchain->frontBuffer;
2149 This->lastActiveRenderTarget = swapchain->frontBuffer;
2151 IWineD3DSurface_AddRef(This->render_targets[0]);
2152 This->activeContext = swapchain->context[0];
2153 This->lastThread = GetCurrentThreadId();
2155 /* Depth Stencil support */
2156 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2157 if (NULL != This->stencilBufferTarget) {
2158 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2161 hr = This->shader_backend->shader_alloc_private(iface);
2163 TRACE("Shader private data couldn't be allocated\n");
2166 hr = This->frag_pipe->alloc_private(iface);
2168 TRACE("Fragment pipeline private data couldn't be allocated\n");
2171 hr = This->blitter->alloc_private(iface);
2173 TRACE("Blitter private data couldn't be allocated\n");
2177 /* Set up some starting GL setup */
2179 /* Setup all the devices defaults */
2180 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2181 create_dummy_textures(This);
2185 { /* Set a default viewport */
2189 vp.Width = pPresentationParameters->BackBufferWidth;
2190 vp.Height = pPresentationParameters->BackBufferHeight;
2193 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2196 /* Initialize the current view state */
2197 This->view_ident = 1;
2198 This->contexts[0]->last_was_rhw = 0;
2199 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2200 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2202 switch(wined3d_settings.offscreen_rendering_mode) {
2205 This->offscreenBuffer = GL_BACK;
2208 case ORM_BACKBUFFER:
2210 if(This->activeContext->aux_buffers > 0) {
2211 TRACE("Using auxilliary buffer for offscreen rendering\n");
2212 This->offscreenBuffer = GL_AUX0;
2214 TRACE("Using back buffer for offscreen rendering\n");
2215 This->offscreenBuffer = GL_BACK;
2220 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2223 /* Clear the screen */
2224 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2225 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2228 This->d3d_initialized = TRUE;
2230 if(wined3d_settings.logo) {
2231 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2233 This->highest_dirty_ps_const = 0;
2234 This->highest_dirty_vs_const = 0;
2238 HeapFree(GetProcessHeap(), 0, This->render_targets);
2239 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2240 HeapFree(GetProcessHeap(), 0, This->swapchains);
2241 This->NumberOfSwapChains = 0;
2242 if(This->palettes) {
2243 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2244 HeapFree(GetProcessHeap(), 0, This->palettes);
2246 This->NumberOfPalettes = 0;
2248 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2250 if(This->stateBlock) {
2251 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2252 This->stateBlock = NULL;
2254 if (This->blit_priv) {
2255 This->blitter->free_private(iface);
2257 if (This->fragment_priv) {
2258 This->frag_pipe->free_private(iface);
2260 if (This->shader_priv) {
2261 This->shader_backend->shader_free_private(iface);
2266 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2267 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2268 IWineD3DSwapChainImpl *swapchain = NULL;
2271 /* Setup the implicit swapchain */
2272 TRACE("Creating implicit swapchain\n");
2273 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2274 if (FAILED(hr) || !swapchain) {
2275 WARN("Failed to create implicit swapchain\n");
2279 This->NumberOfSwapChains = 1;
2280 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2281 if(!This->swapchains) {
2282 ERR("Out of memory!\n");
2285 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2289 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2293 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2297 TRACE("(%p)\n", This);
2299 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2301 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2302 * it was created. Thus make sure a context is active for the glDelete* calls
2304 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2306 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2308 TRACE("Deleting high order patches\n");
2309 for(i = 0; i < PATCHMAP_SIZE; i++) {
2310 struct list *e1, *e2;
2311 struct WineD3DRectPatch *patch;
2312 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2313 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2314 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2318 /* Delete the palette conversion shader if it is around */
2319 if(This->paletteConversionShader) {
2321 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2323 This->paletteConversionShader = 0;
2326 /* Delete the pbuffer context if there is any */
2327 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2329 /* Delete the mouse cursor texture */
2330 if(This->cursorTexture) {
2332 glDeleteTextures(1, &This->cursorTexture);
2334 This->cursorTexture = 0;
2337 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2338 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2340 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2341 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2344 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2345 * private data, it might contain opengl pointers
2347 if(This->depth_blt_texture) {
2348 glDeleteTextures(1, &This->depth_blt_texture);
2349 This->depth_blt_texture = 0;
2351 if (This->depth_blt_rb) {
2352 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2353 This->depth_blt_rb = 0;
2354 This->depth_blt_rb_w = 0;
2355 This->depth_blt_rb_h = 0;
2358 /* Release the update stateblock */
2359 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2360 if(This->updateStateBlock != This->stateBlock)
2361 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2363 This->updateStateBlock = NULL;
2365 { /* because were not doing proper internal refcounts releasing the primary state block
2366 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2367 to set this->stateBlock = NULL; first */
2368 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2369 This->stateBlock = NULL;
2371 /* Release the stateblock */
2372 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2373 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2377 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2378 This->blitter->free_private(iface);
2379 This->frag_pipe->free_private(iface);
2380 This->shader_backend->shader_free_private(iface);
2382 /* Release the buffers (with sanity checks)*/
2383 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2384 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2385 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2386 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2388 This->stencilBufferTarget = NULL;
2390 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2391 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2392 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2394 TRACE("Setting rendertarget to NULL\n");
2395 This->render_targets[0] = NULL;
2397 if (This->auto_depth_stencil_buffer) {
2398 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2399 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2401 This->auto_depth_stencil_buffer = NULL;
2404 for(i=0; i < This->NumberOfSwapChains; i++) {
2405 TRACE("Releasing the implicit swapchain %d\n", i);
2406 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2407 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2411 HeapFree(GetProcessHeap(), 0, This->swapchains);
2412 This->swapchains = NULL;
2413 This->NumberOfSwapChains = 0;
2415 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2416 HeapFree(GetProcessHeap(), 0, This->palettes);
2417 This->palettes = NULL;
2418 This->NumberOfPalettes = 0;
2420 HeapFree(GetProcessHeap(), 0, This->render_targets);
2421 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2422 This->render_targets = NULL;
2423 This->draw_buffers = NULL;
2425 This->d3d_initialized = FALSE;
2429 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2433 for(i=0; i < This->NumberOfSwapChains; i++) {
2434 TRACE("Releasing the implicit swapchain %d\n", i);
2435 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2436 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2440 HeapFree(GetProcessHeap(), 0, This->swapchains);
2441 This->swapchains = NULL;
2442 This->NumberOfSwapChains = 0;
2446 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2447 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2448 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2450 * There is no way to deactivate thread safety once it is enabled.
2452 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2453 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2455 /*For now just store the flag(needed in case of ddraw) */
2456 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2461 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2462 const WINED3DDISPLAYMODE* pMode) {
2464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2466 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2469 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2471 /* Resize the screen even without a window:
2472 * The app could have unset it with SetCooperativeLevel, but not called
2473 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2474 * but we don't have any hwnd
2477 memset(&devmode, 0, sizeof(devmode));
2478 devmode.dmSize = sizeof(devmode);
2479 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2480 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2481 devmode.dmPelsWidth = pMode->Width;
2482 devmode.dmPelsHeight = pMode->Height;
2484 devmode.dmDisplayFrequency = pMode->RefreshRate;
2485 if (pMode->RefreshRate != 0) {
2486 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2489 /* Only change the mode if necessary */
2490 if( (This->ddraw_width == pMode->Width) &&
2491 (This->ddraw_height == pMode->Height) &&
2492 (This->ddraw_format == pMode->Format) &&
2493 (pMode->RefreshRate == 0) ) {
2497 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2498 if (ret != DISP_CHANGE_SUCCESSFUL) {
2499 if(devmode.dmDisplayFrequency != 0) {
2500 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2501 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2502 devmode.dmDisplayFrequency = 0;
2503 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2505 if(ret != DISP_CHANGE_SUCCESSFUL) {
2506 return WINED3DERR_NOTAVAILABLE;
2510 /* Store the new values */
2511 This->ddraw_width = pMode->Width;
2512 This->ddraw_height = pMode->Height;
2513 This->ddraw_format = pMode->Format;
2515 /* And finally clip mouse to our screen */
2516 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2517 ClipCursor(&clip_rc);
2522 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2524 *ppD3D= This->wineD3D;
2525 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2526 IWineD3D_AddRef(*ppD3D);
2530 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2533 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2534 (This->adapter->TextureRam/(1024*1024)),
2535 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2536 /* return simulated texture memory left */
2537 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2545 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2546 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2548 /* Update the current state block */
2549 This->updateStateBlock->changed.fvf = TRUE;
2551 if(This->updateStateBlock->fvf == fvf) {
2552 TRACE("Application is setting the old fvf over, nothing to do\n");
2556 This->updateStateBlock->fvf = fvf;
2557 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2558 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2563 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2564 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2565 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2566 *pfvf = This->stateBlock->fvf;
2571 * Get / Set Stream Source
2573 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2575 IWineD3DVertexBuffer *oldSrc;
2577 if (StreamNumber >= MAX_STREAMS) {
2578 WARN("Stream out of range %d\n", StreamNumber);
2579 return WINED3DERR_INVALIDCALL;
2580 } else if(OffsetInBytes & 0x3) {
2581 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2582 return WINED3DERR_INVALIDCALL;
2585 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2586 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2588 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2590 if(oldSrc == pStreamData &&
2591 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2592 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2593 TRACE("Application is setting the old values over, nothing to do\n");
2597 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2599 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2600 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2603 /* Handle recording of state blocks */
2604 if (This->isRecordingState) {
2605 TRACE("Recording... not performing anything\n");
2606 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2607 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2611 /* Need to do a getParent and pass the references up */
2612 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2613 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2614 so for now, just count internally */
2615 if (pStreamData != NULL) {
2616 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2617 InterlockedIncrement(&vbImpl->bindCount);
2618 IWineD3DVertexBuffer_AddRef(pStreamData);
2620 if (oldSrc != NULL) {
2621 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2622 IWineD3DVertexBuffer_Release(oldSrc);
2625 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2630 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2633 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2634 This->stateBlock->streamSource[StreamNumber],
2635 This->stateBlock->streamOffset[StreamNumber],
2636 This->stateBlock->streamStride[StreamNumber]);
2638 if (StreamNumber >= MAX_STREAMS) {
2639 WARN("Stream out of range %d\n", StreamNumber);
2640 return WINED3DERR_INVALIDCALL;
2642 *pStream = This->stateBlock->streamSource[StreamNumber];
2643 *pStride = This->stateBlock->streamStride[StreamNumber];
2645 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2648 if (*pStream != NULL) {
2649 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2654 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2655 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2656 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2657 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2659 /* Verify input at least in d3d9 this is invalid*/
2660 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2661 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2664 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2665 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2666 return WINED3DERR_INVALIDCALL;
2669 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL;
2673 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2674 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2676 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2677 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2679 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2680 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2681 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2687 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2690 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2691 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2693 TRACE("(%p) : returning %d\n", This, *Divider);
2699 * Get / Set & Multiply Transform
2701 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 /* Most of this routine, comments included copied from ddraw tree initially: */
2705 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2707 /* Handle recording of state blocks */
2708 if (This->isRecordingState) {
2709 TRACE("Recording... not performing anything\n");
2710 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2711 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2716 * If the new matrix is the same as the current one,
2717 * we cut off any further processing. this seems to be a reasonable
2718 * optimization because as was noticed, some apps (warcraft3 for example)
2719 * tend towards setting the same matrix repeatedly for some reason.
2721 * From here on we assume that the new matrix is different, wherever it matters.
2723 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2724 TRACE("The app is setting the same matrix over again\n");
2727 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2731 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2732 where ViewMat = Camera space, WorldMat = world space.
2734 In OpenGL, camera and world space is combined into GL_MODELVIEW
2735 matrix. The Projection matrix stay projection matrix.
2738 /* Capture the times we can just ignore the change for now */
2739 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2740 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2741 /* Handled by the state manager */
2744 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2748 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2751 *pMatrix = This->stateBlock->transforms[State];
2755 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2756 const WINED3DMATRIX *mat = NULL;
2759 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2760 * below means it will be recorded in a state block change, but it
2761 * works regardless where it is recorded.
2762 * If this is found to be wrong, change to StateBlock.
2764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2765 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2767 if (State < HIGHEST_TRANSFORMSTATE)
2769 mat = &This->updateStateBlock->transforms[State];
2771 FIXME("Unhandled transform state!!\n");
2774 multiply_matrix(&temp, mat, pMatrix);
2776 /* Apply change via set transform - will reapply to eg. lights this way */
2777 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2783 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2784 you can reference any indexes you want as long as that number max are enabled at any
2785 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2786 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2787 but when recording, just build a chain pretty much of commands to be replayed. */
2789 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2791 PLIGHTINFOEL *object = NULL;
2792 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2795 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2796 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2798 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2802 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2803 return WINED3DERR_INVALIDCALL;
2806 switch(pLight->Type) {
2807 case WINED3DLIGHT_POINT:
2808 case WINED3DLIGHT_SPOT:
2809 case WINED3DLIGHT_PARALLELPOINT:
2810 case WINED3DLIGHT_GLSPOT:
2811 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2814 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2815 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2816 return WINED3DERR_INVALIDCALL;
2820 case WINED3DLIGHT_DIRECTIONAL:
2821 /* Ignores attenuation */
2825 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2826 return WINED3DERR_INVALIDCALL;
2829 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2830 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2831 if(object->OriginalIndex == Index) break;
2836 TRACE("Adding new light\n");
2837 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2839 ERR("Out of memory error when allocating a light\n");
2840 return E_OUTOFMEMORY;
2842 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2843 object->glIndex = -1;
2844 object->OriginalIndex = Index;
2845 object->changed = TRUE;
2848 /* Initialize the object */
2849 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,
2850 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2851 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2852 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2853 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2854 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2855 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2857 /* Save away the information */
2858 object->OriginalParms = *pLight;
2860 switch (pLight->Type) {
2861 case WINED3DLIGHT_POINT:
2863 object->lightPosn[0] = pLight->Position.x;
2864 object->lightPosn[1] = pLight->Position.y;
2865 object->lightPosn[2] = pLight->Position.z;
2866 object->lightPosn[3] = 1.0f;
2867 object->cutoff = 180.0f;
2871 case WINED3DLIGHT_DIRECTIONAL:
2873 object->lightPosn[0] = -pLight->Direction.x;
2874 object->lightPosn[1] = -pLight->Direction.y;
2875 object->lightPosn[2] = -pLight->Direction.z;
2876 object->lightPosn[3] = 0.0;
2877 object->exponent = 0.0f;
2878 object->cutoff = 180.0f;
2881 case WINED3DLIGHT_SPOT:
2883 object->lightPosn[0] = pLight->Position.x;
2884 object->lightPosn[1] = pLight->Position.y;
2885 object->lightPosn[2] = pLight->Position.z;
2886 object->lightPosn[3] = 1.0;
2889 object->lightDirn[0] = pLight->Direction.x;
2890 object->lightDirn[1] = pLight->Direction.y;
2891 object->lightDirn[2] = pLight->Direction.z;
2892 object->lightDirn[3] = 1.0;
2895 * opengl-ish and d3d-ish spot lights use too different models for the
2896 * light "intensity" as a function of the angle towards the main light direction,
2897 * so we only can approximate very roughly.
2898 * however spot lights are rather rarely used in games (if ever used at all).
2899 * furthermore if still used, probably nobody pays attention to such details.
2901 if (pLight->Falloff == 0) {
2902 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2903 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2904 * will always be 1.0 for both of them, and we don't have to care for the
2905 * rest of the rather complex calculation
2907 object->exponent = 0;
2909 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2910 if (rho < 0.0001) rho = 0.0001f;
2911 object->exponent = -0.3/log(cos(rho/2));
2913 if (object->exponent > 128.0) {
2914 object->exponent = 128.0;
2916 object->cutoff = pLight->Phi*90/M_PI;
2922 FIXME("Unrecognized light type %d\n", pLight->Type);
2925 /* Update the live definitions if the light is currently assigned a glIndex */
2926 if (object->glIndex != -1 && !This->isRecordingState) {
2927 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2932 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2933 PLIGHTINFOEL *lightInfo = NULL;
2934 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2935 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2937 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2939 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2940 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2941 if(lightInfo->OriginalIndex == Index) break;
2945 if (lightInfo == NULL) {
2946 TRACE("Light information requested but light not defined\n");
2947 return WINED3DERR_INVALIDCALL;
2950 *pLight = lightInfo->OriginalParms;
2955 * Get / Set Light Enable
2956 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2958 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2959 PLIGHTINFOEL *lightInfo = NULL;
2960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2961 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2963 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2965 /* Tests show true = 128...not clear why */
2966 Enable = Enable? 128: 0;
2968 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2969 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2970 if(lightInfo->OriginalIndex == Index) break;
2973 TRACE("Found light: %p\n", lightInfo);
2975 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2976 if (lightInfo == NULL) {
2978 TRACE("Light enabled requested but light not defined, so defining one!\n");
2979 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2981 /* Search for it again! Should be fairly quick as near head of list */
2982 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2983 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2984 if(lightInfo->OriginalIndex == Index) break;
2987 if (lightInfo == NULL) {
2988 FIXME("Adding default lights has failed dismally\n");
2989 return WINED3DERR_INVALIDCALL;
2993 lightInfo->enabledChanged = TRUE;
2995 if(lightInfo->glIndex != -1) {
2996 if(!This->isRecordingState) {
2997 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3000 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3001 lightInfo->glIndex = -1;
3003 TRACE("Light already disabled, nothing to do\n");
3005 lightInfo->enabled = FALSE;
3007 lightInfo->enabled = TRUE;
3008 if (lightInfo->glIndex != -1) {
3010 TRACE("Nothing to do as light was enabled\n");
3013 /* Find a free gl light */
3014 for(i = 0; i < This->maxConcurrentLights; i++) {
3015 if(This->updateStateBlock->activeLights[i] == NULL) {
3016 This->updateStateBlock->activeLights[i] = lightInfo;
3017 lightInfo->glIndex = i;
3021 if(lightInfo->glIndex == -1) {
3022 /* Our tests show that Windows returns D3D_OK in this situation, even with
3023 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3024 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3025 * as well for those lights.
3027 * TODO: Test how this affects rendering
3029 FIXME("Too many concurrently active lights\n");
3033 /* i == lightInfo->glIndex */
3034 if(!This->isRecordingState) {
3035 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3043 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3045 PLIGHTINFOEL *lightInfo = NULL;
3046 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3048 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3049 TRACE("(%p) : for idx(%d)\n", This, Index);
3051 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3052 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3053 if(lightInfo->OriginalIndex == Index) break;
3057 if (lightInfo == NULL) {
3058 TRACE("Light enabled state requested but light not defined\n");
3059 return WINED3DERR_INVALIDCALL;
3061 /* true is 128 according to SetLightEnable */
3062 *pEnable = lightInfo->enabled ? 128 : 0;
3067 * Get / Set Clip Planes
3069 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3070 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3071 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3073 /* Validate Index */
3074 if (Index >= GL_LIMITS(clipplanes)) {
3075 TRACE("Application has requested clipplane this device doesn't support\n");
3076 return WINED3DERR_INVALIDCALL;
3079 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3081 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3082 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3083 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3084 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3085 TRACE("Application is setting old values over, nothing to do\n");
3089 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3090 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3091 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3092 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3094 /* Handle recording of state blocks */
3095 if (This->isRecordingState) {
3096 TRACE("Recording... not performing anything\n");
3100 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3105 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3107 TRACE("(%p) : for idx %d\n", This, Index);
3109 /* Validate Index */
3110 if (Index >= GL_LIMITS(clipplanes)) {
3111 TRACE("Application has requested clipplane this device doesn't support\n");
3112 return WINED3DERR_INVALIDCALL;
3115 pPlane[0] = This->stateBlock->clipplane[Index][0];
3116 pPlane[1] = This->stateBlock->clipplane[Index][1];
3117 pPlane[2] = This->stateBlock->clipplane[Index][2];
3118 pPlane[3] = This->stateBlock->clipplane[Index][3];
3123 * Get / Set Clip Plane Status
3124 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3126 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 FIXME("(%p) : stub\n", This);
3129 if (NULL == pClipStatus) {
3130 return WINED3DERR_INVALIDCALL;
3132 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3133 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3137 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3138 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3139 FIXME("(%p) : stub\n", This);
3140 if (NULL == pClipStatus) {
3141 return WINED3DERR_INVALIDCALL;
3143 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3144 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3149 * Get / Set Material
3151 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3154 This->updateStateBlock->changed.material = TRUE;
3155 This->updateStateBlock->material = *pMaterial;
3157 /* Handle recording of state blocks */
3158 if (This->isRecordingState) {
3159 TRACE("Recording... not performing anything\n");
3163 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3167 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3169 *pMaterial = This->updateStateBlock->material;
3170 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3171 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3172 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3173 pMaterial->Ambient.b, pMaterial->Ambient.a);
3174 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3175 pMaterial->Specular.b, pMaterial->Specular.a);
3176 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3177 pMaterial->Emissive.b, pMaterial->Emissive.a);
3178 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3186 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 IWineD3DIndexBuffer *oldIdxs;
3190 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3191 oldIdxs = This->updateStateBlock->pIndexData;
3193 This->updateStateBlock->changed.indices = TRUE;
3194 This->updateStateBlock->pIndexData = pIndexData;
3196 /* Handle recording of state blocks */
3197 if (This->isRecordingState) {
3198 TRACE("Recording... not performing anything\n");
3199 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3200 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3204 if(oldIdxs != pIndexData) {
3205 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3206 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3207 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3212 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3215 *ppIndexData = This->stateBlock->pIndexData;
3217 /* up ref count on ppindexdata */
3219 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3220 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3222 TRACE("(%p) No index data set\n", This);
3224 TRACE("Returning %p\n", *ppIndexData);
3229 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3230 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3231 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3232 TRACE("(%p)->(%d)\n", This, BaseIndex);
3234 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3235 TRACE("Application is setting the old value over, nothing to do\n");
3239 This->updateStateBlock->baseVertexIndex = BaseIndex;
3241 if (This->isRecordingState) {
3242 TRACE("Recording... not performing anything\n");
3245 /* The base vertex index affects the stream sources */
3246 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3250 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3251 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3252 TRACE("(%p) : base_index %p\n", This, base_index);
3254 *base_index = This->stateBlock->baseVertexIndex;
3256 TRACE("Returning %u\n", *base_index);
3262 * Get / Set Viewports
3264 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3267 TRACE("(%p)\n", This);
3268 This->updateStateBlock->changed.viewport = TRUE;
3269 This->updateStateBlock->viewport = *pViewport;
3271 /* Handle recording of state blocks */
3272 if (This->isRecordingState) {
3273 TRACE("Recording... not performing anything\n");
3277 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3278 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3280 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3285 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3287 TRACE("(%p)\n", This);
3288 *pViewport = This->stateBlock->viewport;
3293 * Get / Set Render States
3294 * TODO: Verify against dx9 definitions
3296 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3298 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3299 DWORD oldValue = This->stateBlock->renderState[State];
3301 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3303 This->updateStateBlock->changed.renderState[State] = TRUE;
3304 This->updateStateBlock->renderState[State] = Value;
3306 /* Handle recording of state blocks */
3307 if (This->isRecordingState) {
3308 TRACE("Recording... not performing anything\n");
3312 /* Compared here and not before the assignment to allow proper stateblock recording */
3313 if(Value == oldValue) {
3314 TRACE("Application is setting the old value over, nothing to do\n");
3316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3322 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3323 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3324 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3325 *pValue = This->stateBlock->renderState[State];
3330 * Get / Set Sampler States
3331 * TODO: Verify against dx9 definitions
3334 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3335 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3338 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3339 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3341 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3342 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3345 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3346 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3347 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3350 * SetSampler is designed to allow for more than the standard up to 8 textures
3351 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3352 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3354 * http://developer.nvidia.com/object/General_FAQ.html#t6
3356 * There are two new settings for GForce
3358 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3359 * and the texture one:
3360 * GL_MAX_TEXTURE_COORDS_ARB.
3361 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3364 oldValue = This->stateBlock->samplerState[Sampler][Type];
3365 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3366 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3368 /* Handle recording of state blocks */
3369 if (This->isRecordingState) {
3370 TRACE("Recording... not performing anything\n");
3374 if(oldValue == Value) {
3375 TRACE("Application is setting the old value over, nothing to do\n");
3379 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3384 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3385 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3387 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3388 This, Sampler, debug_d3dsamplerstate(Type), Type);
3390 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3391 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3394 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3395 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3396 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3398 *Value = This->stateBlock->samplerState[Sampler][Type];
3399 TRACE("(%p) : Returning %#x\n", This, *Value);
3404 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3407 This->updateStateBlock->changed.scissorRect = TRUE;
3408 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3409 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3412 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3414 if(This->isRecordingState) {
3415 TRACE("Recording... not performing anything\n");
3419 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3424 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3425 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3427 *pRect = This->updateStateBlock->scissorRect;
3428 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3432 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3433 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3434 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3436 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3438 This->updateStateBlock->vertexDecl = pDecl;
3439 This->updateStateBlock->changed.vertexDecl = TRUE;
3441 if (This->isRecordingState) {
3442 TRACE("Recording... not performing anything\n");
3444 } else if(pDecl == oldDecl) {
3445 /* Checked after the assignment to allow proper stateblock recording */
3446 TRACE("Application is setting the old declaration over, nothing to do\n");
3450 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3454 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3455 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3457 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3459 *ppDecl = This->stateBlock->vertexDecl;
3460 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3464 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3466 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3468 This->updateStateBlock->vertexShader = pShader;
3469 This->updateStateBlock->changed.vertexShader = TRUE;
3471 if (This->isRecordingState) {
3472 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3473 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3474 TRACE("Recording... not performing anything\n");
3476 } else if(oldShader == pShader) {
3477 /* Checked here to allow proper stateblock recording */
3478 TRACE("App is setting the old shader over, nothing to do\n");
3482 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3483 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3484 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3486 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3491 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3492 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3494 if (NULL == ppShader) {
3495 return WINED3DERR_INVALIDCALL;
3497 *ppShader = This->stateBlock->vertexShader;
3498 if( NULL != *ppShader)
3499 IWineD3DVertexShader_AddRef(*ppShader);
3501 TRACE("(%p) : returning %p\n", This, *ppShader);
3505 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3506 IWineD3DDevice *iface,
3508 CONST BOOL *srcData,
3511 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3512 int i, cnt = min(count, MAX_CONST_B - start);
3514 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3515 iface, srcData, start, count);
3517 if (srcData == NULL || cnt < 0)
3518 return WINED3DERR_INVALIDCALL;
3520 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3521 for (i = 0; i < cnt; i++)
3522 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3524 for (i = start; i < cnt + start; ++i) {
3525 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3528 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3533 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3534 IWineD3DDevice *iface,
3539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3540 int cnt = min(count, MAX_CONST_B - start);
3542 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3543 iface, dstData, start, count);
3545 if (dstData == NULL || cnt < 0)
3546 return WINED3DERR_INVALIDCALL;
3548 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3552 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3553 IWineD3DDevice *iface,
3558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3559 int i, cnt = min(count, MAX_CONST_I - start);
3561 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3562 iface, srcData, start, count);
3564 if (srcData == NULL || cnt < 0)
3565 return WINED3DERR_INVALIDCALL;
3567 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3568 for (i = 0; i < cnt; i++)
3569 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3570 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3572 for (i = start; i < cnt + start; ++i) {
3573 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3576 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3581 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3582 IWineD3DDevice *iface,
3587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3588 int cnt = min(count, MAX_CONST_I - start);
3590 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3591 iface, dstData, start, count);
3593 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3594 return WINED3DERR_INVALIDCALL;
3596 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3600 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3601 IWineD3DDevice *iface,
3603 CONST float *srcData,
3606 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3609 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3610 iface, srcData, start, count);
3612 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3613 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3614 return WINED3DERR_INVALIDCALL;
3616 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3618 for (i = 0; i < count; i++)
3619 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3620 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3623 for (i = start; i < count + start; ++i) {
3624 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3625 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3626 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3627 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3628 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3630 ptr->idx[ptr->count++] = i;
3631 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3640 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3641 IWineD3DDevice *iface,
3643 CONST float *srcData,
3646 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3649 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3650 iface, srcData, start, count);
3652 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3653 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3654 return WINED3DERR_INVALIDCALL;
3656 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3658 for (i = 0; i < count; i++)
3659 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3660 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3663 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3664 * context. On a context switch the old context will be fully dirtified
3666 memset(This->activeContext->vshader_const_dirty + start, 1,
3667 sizeof(*This->activeContext->vshader_const_dirty) * count);
3668 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3670 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3675 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3676 IWineD3DDevice *iface,
3681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3682 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3684 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3685 iface, dstData, start, count);
3687 if (dstData == NULL || cnt < 0)
3688 return WINED3DERR_INVALIDCALL;
3690 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3694 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3696 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3701 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3702 int i = This->rev_tex_unit_map[unit];
3703 int j = This->texUnitMap[stage];
3705 This->texUnitMap[stage] = unit;
3706 if (i != -1 && i != stage) {
3707 This->texUnitMap[i] = -1;
3710 This->rev_tex_unit_map[unit] = stage;
3711 if (j != -1 && j != unit) {
3712 This->rev_tex_unit_map[j] = -1;
3716 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3719 for (i = 0; i < MAX_TEXTURES; ++i) {
3720 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3721 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3722 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3723 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3724 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3725 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3726 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3727 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3729 if (color_op == WINED3DTOP_DISABLE) {
3730 /* Not used, and disable higher stages */
3731 while (i < MAX_TEXTURES) {
3732 This->fixed_function_usage_map[i] = FALSE;
3738 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3739 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3740 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3741 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3742 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3743 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3744 This->fixed_function_usage_map[i] = TRUE;
3746 This->fixed_function_usage_map[i] = FALSE;
3749 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3750 This->fixed_function_usage_map[i+1] = TRUE;
3755 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3758 device_update_fixed_function_usage_map(This);
3760 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3761 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3762 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3763 if (!This->fixed_function_usage_map[i]) continue;
3765 if (This->texUnitMap[i] != i) {
3766 device_map_stage(This, i, i);
3767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3768 markTextureStagesDirty(This, i);
3774 /* Now work out the mapping */
3776 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3777 if (!This->fixed_function_usage_map[i]) continue;
3779 if (This->texUnitMap[i] != tex) {
3780 device_map_stage(This, i, tex);
3781 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3782 markTextureStagesDirty(This, i);
3789 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3790 const DWORD *sampler_tokens =
3791 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3794 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3795 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3796 device_map_stage(This, i, i);
3797 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3798 if (i < MAX_TEXTURES) {
3799 markTextureStagesDirty(This, i);
3805 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3806 const DWORD *vshader_sampler_tokens, int unit)
3808 int current_mapping = This->rev_tex_unit_map[unit];
3810 if (current_mapping == -1) {
3811 /* Not currently used */
3815 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3816 /* Used by a fragment sampler */
3818 if (!pshader_sampler_tokens) {
3819 /* No pixel shader, check fixed function */
3820 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3823 /* Pixel shader, check the shader's sampler map */
3824 return !pshader_sampler_tokens[current_mapping];
3827 /* Used by a vertex sampler */
3828 return !vshader_sampler_tokens[current_mapping];
3831 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3832 const DWORD *vshader_sampler_tokens =
3833 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3834 const DWORD *pshader_sampler_tokens = NULL;
3835 int start = GL_LIMITS(combined_samplers) - 1;
3839 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3841 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3842 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3843 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3846 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3847 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3848 if (vshader_sampler_tokens[i]) {
3849 if (This->texUnitMap[vsampler_idx] != -1) {
3850 /* Already mapped somewhere */
3854 while (start >= 0) {
3855 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3856 device_map_stage(This, vsampler_idx, start);
3857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3869 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3870 BOOL vs = use_vs(This);
3871 BOOL ps = use_ps(This);
3874 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3875 * that would be really messy and require shader recompilation
3876 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3877 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3880 device_map_psamplers(This);
3882 device_map_fixed_function_samplers(This);
3886 device_map_vsamplers(This, ps);
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3892 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3893 This->updateStateBlock->pixelShader = pShader;
3894 This->updateStateBlock->changed.pixelShader = TRUE;
3896 /* Handle recording of state blocks */
3897 if (This->isRecordingState) {
3898 TRACE("Recording... not performing anything\n");
3901 if (This->isRecordingState) {
3902 TRACE("Recording... not performing anything\n");
3903 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3904 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3908 if(pShader == oldShader) {
3909 TRACE("App is setting the old pixel shader over, nothing to do\n");
3913 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3914 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3916 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3922 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 if (NULL == ppShader) {
3926 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3927 return WINED3DERR_INVALIDCALL;
3930 *ppShader = This->stateBlock->pixelShader;
3931 if (NULL != *ppShader) {
3932 IWineD3DPixelShader_AddRef(*ppShader);
3934 TRACE("(%p) : returning %p\n", This, *ppShader);
3938 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3939 IWineD3DDevice *iface,
3941 CONST BOOL *srcData,
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 int i, cnt = min(count, MAX_CONST_B - start);
3947 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3948 iface, srcData, start, count);
3950 if (srcData == NULL || cnt < 0)
3951 return WINED3DERR_INVALIDCALL;
3953 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3954 for (i = 0; i < cnt; i++)
3955 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3967 IWineD3DDevice *iface,
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_B - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3986 IWineD3DDevice *iface,
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int i, cnt = min(count, MAX_CONST_I - start);
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 if (srcData == NULL || cnt < 0)
3998 return WINED3DERR_INVALIDCALL;
4000 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4001 for (i = 0; i < cnt; i++)
4002 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4003 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4005 for (i = start; i < cnt + start; ++i) {
4006 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4014 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4015 IWineD3DDevice *iface,
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 int cnt = min(count, MAX_CONST_I - start);
4023 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4024 iface, dstData, start, count);
4026 if (dstData == NULL || cnt < 0)
4027 return WINED3DERR_INVALIDCALL;
4029 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4033 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4034 IWineD3DDevice *iface,
4036 CONST float *srcData,
4039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4042 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4043 iface, srcData, start, count);
4045 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4046 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4047 return WINED3DERR_INVALIDCALL;
4049 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4051 for (i = 0; i < count; i++)
4052 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4053 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4056 for (i = start; i < count + start; ++i) {
4057 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4058 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4059 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4060 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4061 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4063 ptr->idx[ptr->count++] = i;
4064 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4073 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4074 IWineD3DDevice *iface,
4076 CONST float *srcData,
4079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4083 iface, srcData, start, count);
4085 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4086 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4087 return WINED3DERR_INVALIDCALL;
4089 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4091 for (i = 0; i < count; i++)
4092 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4093 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4096 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4097 * context. On a context switch the old context will be fully dirtified
4099 memset(This->activeContext->pshader_const_dirty + start, 1,
4100 sizeof(*This->activeContext->pshader_const_dirty) * count);
4101 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4108 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4109 IWineD3DDevice *iface,
4114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4115 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4117 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4118 iface, dstData, start, count);
4120 if (dstData == NULL || cnt < 0)
4121 return WINED3DERR_INVALIDCALL;
4123 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4127 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4128 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4129 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4131 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4133 DWORD DestFVF = dest->fvf;
4135 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4139 if (lpStrideData->u.s.normal.lpData) {
4140 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4143 if (lpStrideData->u.s.position.lpData == NULL) {
4144 ERR("Source has no position mask\n");
4145 return WINED3DERR_INVALIDCALL;
4148 /* We might access VBOs from this code, so hold the lock */
4151 if (dest->resource.allocatedMemory == NULL) {
4152 /* This may happen if we do direct locking into a vbo. Unlikely,
4153 * but theoretically possible(ddraw processvertices test)
4155 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4156 if(!dest->resource.allocatedMemory) {
4158 ERR("Out of memory\n");
4159 return E_OUTOFMEMORY;
4163 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4164 checkGLcall("glBindBufferARB");
4165 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4167 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4169 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4170 checkGLcall("glUnmapBufferARB");
4174 /* Get a pointer into the destination vbo(create one if none exists) and
4175 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4177 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4178 dest->Flags |= VBFLAG_CREATEVBO;
4179 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4183 unsigned char extrabytes = 0;
4184 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4185 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4186 * this may write 4 extra bytes beyond the area that should be written
4188 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4189 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4190 if(!dest_conv_addr) {
4191 ERR("Out of memory\n");
4192 /* Continue without storing converted vertices */
4194 dest_conv = dest_conv_addr;
4198 * a) WINED3DRS_CLIPPING is enabled
4199 * b) WINED3DVOP_CLIP is passed
4201 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4202 static BOOL warned = FALSE;
4204 * The clipping code is not quite correct. Some things need
4205 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4206 * so disable clipping for now.
4207 * (The graphics in Half-Life are broken, and my processvertices
4208 * test crashes with IDirect3DDevice3)
4214 FIXME("Clipping is broken and disabled for now\n");
4216 } else doClip = FALSE;
4217 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4219 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4222 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4223 WINED3DTS_PROJECTION,
4225 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4226 WINED3DTS_WORLDMATRIX(0),
4229 TRACE("View mat:\n");
4230 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);
4231 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);
4232 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);
4233 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);
4235 TRACE("Proj mat:\n");
4236 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);
4237 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);
4238 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);
4239 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);
4241 TRACE("World mat:\n");
4242 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);
4243 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);
4244 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);
4245 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);
4247 /* Get the viewport */
4248 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4249 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4250 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4252 multiply_matrix(&mat,&view_mat,&world_mat);
4253 multiply_matrix(&mat,&proj_mat,&mat);
4255 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4257 for (i = 0; i < dwCount; i+= 1) {
4258 unsigned int tex_index;
4260 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4261 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4262 /* The position first */
4264 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4266 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4268 /* Multiplication with world, view and projection matrix */
4269 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);
4270 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);
4271 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);
4272 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);
4274 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4276 /* WARNING: The following things are taken from d3d7 and were not yet checked
4277 * against d3d8 or d3d9!
4280 /* Clipping conditions: From msdn
4282 * A vertex is clipped if it does not match the following requirements
4286 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4288 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4289 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4294 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4295 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4298 /* "Normal" viewport transformation (not clipped)
4299 * 1) The values are divided by rhw
4300 * 2) The y axis is negative, so multiply it with -1
4301 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4302 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4303 * 4) Multiply x with Width/2 and add Width/2
4304 * 5) The same for the height
4305 * 6) Add the viewpoint X and Y to the 2D coordinates and
4306 * The minimum Z value to z
4307 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4309 * Well, basically it's simply a linear transformation into viewport
4321 z *= vp.MaxZ - vp.MinZ;
4323 x += vp.Width / 2 + vp.X;
4324 y += vp.Height / 2 + vp.Y;
4329 /* That vertex got clipped
4330 * Contrary to OpenGL it is not dropped completely, it just
4331 * undergoes a different calculation.
4333 TRACE("Vertex got clipped\n");
4340 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4341 * outside of the main vertex buffer memory. That needs some more
4346 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4349 ( (float *) dest_ptr)[0] = x;
4350 ( (float *) dest_ptr)[1] = y;
4351 ( (float *) dest_ptr)[2] = z;
4352 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4354 dest_ptr += 3 * sizeof(float);
4356 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4357 dest_ptr += sizeof(float);
4362 ( (float *) dest_conv)[0] = x * w;
4363 ( (float *) dest_conv)[1] = y * w;
4364 ( (float *) dest_conv)[2] = z * w;
4365 ( (float *) dest_conv)[3] = w;
4367 dest_conv += 3 * sizeof(float);
4369 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4370 dest_conv += sizeof(float);
4374 if (DestFVF & WINED3DFVF_PSIZE) {
4375 dest_ptr += sizeof(DWORD);
4376 if(dest_conv) dest_conv += sizeof(DWORD);
4378 if (DestFVF & WINED3DFVF_NORMAL) {
4379 const float *normal =
4380 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4381 /* AFAIK this should go into the lighting information */
4382 FIXME("Didn't expect the destination to have a normal\n");
4383 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4385 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4389 if (DestFVF & WINED3DFVF_DIFFUSE) {
4390 const DWORD *color_d =
4391 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4393 static BOOL warned = FALSE;
4396 ERR("No diffuse color in source, but destination has one\n");
4400 *( (DWORD *) dest_ptr) = 0xffffffff;
4401 dest_ptr += sizeof(DWORD);
4404 *( (DWORD *) dest_conv) = 0xffffffff;
4405 dest_conv += sizeof(DWORD);
4409 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4411 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4412 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4413 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4414 dest_conv += sizeof(DWORD);
4419 if (DestFVF & WINED3DFVF_SPECULAR) {
4420 /* What's the color value in the feedback buffer? */
4421 const DWORD *color_s =
4422 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4424 static BOOL warned = FALSE;
4427 ERR("No specular color in source, but destination has one\n");
4431 *( (DWORD *) dest_ptr) = 0xFF000000;
4432 dest_ptr += sizeof(DWORD);
4435 *( (DWORD *) dest_conv) = 0xFF000000;
4436 dest_conv += sizeof(DWORD);
4440 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4442 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4443 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4444 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4445 dest_conv += sizeof(DWORD);
4450 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4451 const float *tex_coord =
4452 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4453 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4455 ERR("No source texture, but destination requests one\n");
4456 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4457 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4460 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4462 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4469 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4470 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4471 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4472 dwCount * get_flexible_vertex_size(DestFVF),
4474 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4475 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4482 #undef copy_and_next
4484 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4486 WineDirect3DVertexStridedData strided;
4487 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4488 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4491 ERR("Output vertex declaration not implemented yet\n");
4494 /* Need any context to write to the vbo. */
4495 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4497 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4498 * control the streamIsUP flag, thus restore it afterwards.
4500 This->stateBlock->streamIsUP = FALSE;
4501 memset(&strided, 0, sizeof(strided));
4502 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4503 This->stateBlock->streamIsUP = streamWasUP;
4505 if(vbo || SrcStartIndex) {
4507 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4508 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4510 * Also get the start index in, but only loop over all elements if there's something to add at all.
4512 #define FIXSRC(type) \
4513 if(strided.u.s.type.VBO) { \
4514 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4515 strided.u.s.type.VBO = 0; \
4516 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4518 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4522 if(strided.u.s.type.lpData) { \
4523 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4526 FIXSRC(blendWeights);
4527 FIXSRC(blendMatrixIndices);
4532 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4533 FIXSRC(texCoords[i]);
4546 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4550 * Get / Set Texture Stage States
4551 * TODO: Verify against dx9 definitions
4553 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4555 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4557 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4559 if (Stage >= MAX_TEXTURES) {
4560 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4564 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4565 This->updateStateBlock->textureState[Stage][Type] = Value;
4567 if (This->isRecordingState) {
4568 TRACE("Recording... not performing anything\n");
4572 /* Checked after the assignments to allow proper stateblock recording */
4573 if(oldValue == Value) {
4574 TRACE("App is setting the old value over, nothing to do\n");
4578 if(Stage > This->stateBlock->lowest_disabled_stage &&
4579 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4580 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4581 * Changes in other states are important on disabled stages too
4586 if(Type == WINED3DTSS_COLOROP) {
4589 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4590 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4591 * they have to be disabled
4593 * The current stage is dirtified below.
4595 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4596 TRACE("Additionally dirtifying stage %d\n", i);
4597 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4599 This->stateBlock->lowest_disabled_stage = Stage;
4600 TRACE("New lowest disabled: %d\n", Stage);
4601 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4602 /* Previously disabled stage enabled. Stages above it may need enabling
4603 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4604 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4606 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4609 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4610 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4613 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4616 This->stateBlock->lowest_disabled_stage = i;
4617 TRACE("New lowest disabled: %d\n", i);
4621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4626 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4628 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4629 *pValue = This->updateStateBlock->textureState[Stage][Type];
4636 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4638 IWineD3DBaseTexture *oldTexture;
4640 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4642 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4643 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4646 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4647 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4648 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4651 oldTexture = This->updateStateBlock->textures[Stage];
4653 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4654 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4656 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4657 return WINED3DERR_INVALIDCALL;
4660 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4661 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4663 This->updateStateBlock->changed.textures[Stage] = TRUE;
4664 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4665 This->updateStateBlock->textures[Stage] = pTexture;
4667 /* Handle recording of state blocks */
4668 if (This->isRecordingState) {
4669 TRACE("Recording... not performing anything\n");
4673 if(oldTexture == pTexture) {
4674 TRACE("App is setting the same texture again, nothing to do\n");
4678 /** NOTE: MSDN says that setTexture increases the reference count,
4679 * and that the application must set the texture back to null (or have a leaky application),
4680 * This means we should pass the refcount up to the parent
4681 *******************************/
4682 if (NULL != This->updateStateBlock->textures[Stage]) {
4683 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4684 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4686 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4687 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4688 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4689 * so the COLOROP and ALPHAOP have to be dirtified.
4691 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4692 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4694 if(bindCount == 1) {
4695 new->baseTexture.sampler = Stage;
4697 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4701 if (NULL != oldTexture) {
4702 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4703 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4705 IWineD3DBaseTexture_Release(oldTexture);
4706 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4708 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4711 if(bindCount && old->baseTexture.sampler == Stage) {
4713 /* Have to do a search for the other sampler(s) where the texture is bound to
4714 * Shouldn't happen as long as apps bind a texture only to one stage
4716 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4717 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4718 if(This->updateStateBlock->textures[i] == oldTexture) {
4719 old->baseTexture.sampler = i;
4726 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4731 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4734 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4736 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4737 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4740 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4741 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4742 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4745 *ppTexture=This->stateBlock->textures[Stage];
4747 IWineD3DBaseTexture_AddRef(*ppTexture);
4749 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4757 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4758 IWineD3DSurface **ppBackBuffer) {
4759 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4760 IWineD3DSwapChain *swapChain;
4763 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4765 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4766 if (hr == WINED3D_OK) {
4767 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4768 IWineD3DSwapChain_Release(swapChain);
4770 *ppBackBuffer = NULL;
4775 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4777 WARN("(%p) : stub, calling idirect3d for now\n", This);
4778 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4781 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4783 IWineD3DSwapChain *swapChain;
4786 if(iSwapChain > 0) {
4787 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4788 if (hr == WINED3D_OK) {
4789 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4790 IWineD3DSwapChain_Release(swapChain);
4792 FIXME("(%p) Error getting display mode\n", This);
4795 /* Don't read the real display mode,
4796 but return the stored mode instead. X11 can't change the color
4797 depth, and some apps are pretty angry if they SetDisplayMode from
4798 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4800 Also don't relay to the swapchain because with ddraw it's possible
4801 that there isn't a swapchain at all */
4802 pMode->Width = This->ddraw_width;
4803 pMode->Height = This->ddraw_height;
4804 pMode->Format = This->ddraw_format;
4805 pMode->RefreshRate = 0;
4813 * Stateblock related functions
4816 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4818 IWineD3DStateBlockImpl *object;
4819 HRESULT temp_result;
4822 TRACE("(%p)\n", This);
4824 if (This->isRecordingState) {
4825 return WINED3DERR_INVALIDCALL;
4828 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4829 if (NULL == object ) {
4830 FIXME("(%p)Error allocating memory for stateblock\n", This);
4831 return E_OUTOFMEMORY;
4833 TRACE("(%p) created object %p\n", This, object);
4834 object->wineD3DDevice= This;
4835 /** FIXME: object->parent = parent; **/
4836 object->parent = NULL;
4837 object->blockType = WINED3DSBT_RECORDED;
4839 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4841 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4842 list_init(&object->lightMap[i]);
4845 temp_result = allocate_shader_constants(object);
4846 if (WINED3D_OK != temp_result)
4849 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4850 This->updateStateBlock = object;
4851 This->isRecordingState = TRUE;
4853 TRACE("(%p) recording stateblock %p\n",This , object);
4857 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4860 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4862 if (!This->isRecordingState) {
4863 FIXME("(%p) not recording! returning error\n", This);
4864 *ppStateBlock = NULL;
4865 return WINED3DERR_INVALIDCALL;
4868 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4869 if(object->changed.renderState[i]) {
4870 object->contained_render_states[object->num_contained_render_states] = i;
4871 object->num_contained_render_states++;
4874 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4875 if(object->changed.transform[i]) {
4876 object->contained_transform_states[object->num_contained_transform_states] = i;
4877 object->num_contained_transform_states++;
4880 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4881 if(object->changed.vertexShaderConstantsF[i]) {
4882 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4883 object->num_contained_vs_consts_f++;
4886 for(i = 0; i < MAX_CONST_I; i++) {
4887 if (object->changed.vertexShaderConstantsI & (1 << i))
4889 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4890 object->num_contained_vs_consts_i++;
4893 for(i = 0; i < MAX_CONST_B; i++) {
4894 if (object->changed.vertexShaderConstantsB & (1 << i))
4896 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4897 object->num_contained_vs_consts_b++;
4900 for(i = 0; i < MAX_CONST_I; i++) {
4901 if (object->changed.pixelShaderConstantsI & (1 << i))
4903 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4904 object->num_contained_ps_consts_i++;
4907 for(i = 0; i < MAX_CONST_B; i++) {
4908 if (object->changed.pixelShaderConstantsB & (1 << i))
4910 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4911 object->num_contained_ps_consts_b++;
4914 for(i = 0; i < MAX_TEXTURES; i++) {
4915 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4916 if(object->changed.textureState[i][j]) {
4917 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4918 object->contained_tss_states[object->num_contained_tss_states].state = j;
4919 object->num_contained_tss_states++;
4923 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4924 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4925 if(object->changed.samplerState[i][j]) {
4926 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4927 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4928 object->num_contained_sampler_states++;
4933 *ppStateBlock = (IWineD3DStateBlock*) object;
4934 This->isRecordingState = FALSE;
4935 This->updateStateBlock = This->stateBlock;
4936 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4937 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4938 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4943 * Scene related functions
4945 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4946 /* At the moment we have no need for any functionality at the beginning
4948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4949 TRACE("(%p)\n", This);
4952 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4953 return WINED3DERR_INVALIDCALL;
4955 This->inScene = TRUE;
4959 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4960 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4961 TRACE("(%p)\n", This);
4963 if(!This->inScene) {
4964 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4965 return WINED3DERR_INVALIDCALL;
4968 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4969 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4971 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4975 This->inScene = FALSE;
4979 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4980 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4981 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4982 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4983 IWineD3DSwapChain *swapChain = NULL;
4985 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4987 TRACE("(%p) Presenting the frame\n", This);
4989 for(i = 0 ; i < swapchains ; i ++) {
4991 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4992 TRACE("presentinng chain %d, %p\n", i, swapChain);
4993 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4994 IWineD3DSwapChain_Release(swapChain);
5000 /* Not called from the VTable (internal subroutine) */
5001 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5002 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5003 float Z, DWORD Stencil) {
5004 GLbitfield glMask = 0;
5006 WINED3DRECT curRect;
5008 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5009 UINT drawable_width, drawable_height;
5010 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5011 IWineD3DSwapChainImpl *swapchain = NULL;
5013 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5014 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5015 * for the cleared parts, and the untouched parts.
5017 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5018 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5019 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5020 * checking all this if the dest surface is in the drawable anyway.
5022 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5024 if(vp->X != 0 || vp->Y != 0 ||
5025 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5026 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5029 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5030 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5031 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5032 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5033 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5036 if(Count > 0 && pRects && (
5037 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5038 pRects[0].x2 < target->currentDesc.Width ||
5039 pRects[0].y2 < target->currentDesc.Height)) {
5040 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5047 target->get_drawable_size(target, &drawable_width, &drawable_height);
5049 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5052 /* Only set the values up once, as they are not changing */
5053 if (Flags & WINED3DCLEAR_STENCIL) {
5054 glClearStencil(Stencil);
5055 checkGLcall("glClearStencil");
5056 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5057 glStencilMask(0xFFFFFFFF);
5060 if (Flags & WINED3DCLEAR_ZBUFFER) {
5061 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5062 glDepthMask(GL_TRUE);
5064 checkGLcall("glClearDepth");
5065 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5068 if (vp->X != 0 || vp->Y != 0 ||
5069 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5070 surface_load_ds_location(This->stencilBufferTarget, location);
5072 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5073 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5074 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5075 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5076 surface_load_ds_location(This->stencilBufferTarget, location);
5078 else if (Count > 0 && pRects && (
5079 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5080 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5081 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5082 surface_load_ds_location(This->stencilBufferTarget, location);
5086 if (Flags & WINED3DCLEAR_TARGET) {
5087 TRACE("Clearing screen with glClear to color %x\n", Color);
5088 glClearColor(D3DCOLOR_R(Color),
5092 checkGLcall("glClearColor");
5094 /* Clear ALL colors! */
5095 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5096 glMask = glMask | GL_COLOR_BUFFER_BIT;
5099 vp_rect.left = vp->X;
5100 vp_rect.top = vp->Y;
5101 vp_rect.right = vp->X + vp->Width;
5102 vp_rect.bottom = vp->Y + vp->Height;
5103 if (!(Count > 0 && pRects)) {
5104 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5105 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5107 if(This->render_offscreen) {
5108 glScissor(vp_rect.left, vp_rect.top,
5109 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5111 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5112 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5114 checkGLcall("glScissor");
5116 checkGLcall("glClear");
5118 /* Now process each rect in turn */
5119 for (i = 0; i < Count; i++) {
5120 /* Note gl uses lower left, width/height */
5121 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5122 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5123 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5125 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5126 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5127 curRect.x1, (target->currentDesc.Height - curRect.y2),
5128 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5130 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5131 * The rectangle is not cleared, no error is returned, but further rectanlges are
5132 * still cleared if they are valid
5134 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5135 TRACE("Rectangle with negative dimensions, ignoring\n");
5139 if(This->render_offscreen) {
5140 glScissor(curRect.x1, curRect.y1,
5141 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5143 glScissor(curRect.x1, drawable_height - curRect.y2,
5144 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5146 checkGLcall("glScissor");
5149 checkGLcall("glClear");
5153 /* Restore the old values (why..?) */
5154 if (Flags & WINED3DCLEAR_STENCIL) {
5155 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5157 if (Flags & WINED3DCLEAR_TARGET) {
5158 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5159 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5160 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5161 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5162 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5164 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5165 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5167 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5169 if (Flags & WINED3DCLEAR_ZBUFFER) {
5170 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5171 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5172 surface_modify_ds_location(This->stencilBufferTarget, location);
5177 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5178 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5181 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5187 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5188 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5189 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5190 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5192 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5193 Count, pRects, Flags, Color, Z, Stencil);
5195 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5196 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5197 /* TODO: What about depth stencil buffers without stencil bits? */
5198 return WINED3DERR_INVALIDCALL;
5201 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5207 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5208 UINT PrimitiveCount) {
5210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5212 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5213 debug_d3dprimitivetype(PrimitiveType),
5214 StartVertex, PrimitiveCount);
5216 if(!This->stateBlock->vertexDecl) {
5217 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5218 return WINED3DERR_INVALIDCALL;
5221 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5222 if(This->stateBlock->streamIsUP) {
5223 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5224 This->stateBlock->streamIsUP = FALSE;
5227 if(This->stateBlock->loadBaseVertexIndex != 0) {
5228 This->stateBlock->loadBaseVertexIndex = 0;
5229 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5231 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5232 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5233 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5237 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5238 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5239 WINED3DPRIMITIVETYPE PrimitiveType,
5240 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5244 IWineD3DIndexBuffer *pIB;
5245 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5248 pIB = This->stateBlock->pIndexData;
5250 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5251 * without an index buffer set. (The first time at least...)
5252 * D3D8 simply dies, but I doubt it can do much harm to return
5253 * D3DERR_INVALIDCALL there as well. */
5254 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5255 return WINED3DERR_INVALIDCALL;
5258 if(!This->stateBlock->vertexDecl) {
5259 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5260 return WINED3DERR_INVALIDCALL;
5263 if(This->stateBlock->streamIsUP) {
5264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5265 This->stateBlock->streamIsUP = FALSE;
5267 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5269 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5270 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5271 minIndex, NumVertices, startIndex, primCount);
5273 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5274 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5280 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5281 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5282 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5285 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5286 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5291 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5292 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5293 UINT VertexStreamZeroStride) {
5294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5295 IWineD3DVertexBuffer *vb;
5297 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5298 debug_d3dprimitivetype(PrimitiveType),
5299 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5301 if(!This->stateBlock->vertexDecl) {
5302 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5303 return WINED3DERR_INVALIDCALL;
5306 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5307 vb = This->stateBlock->streamSource[0];
5308 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5309 if(vb) IWineD3DVertexBuffer_Release(vb);
5310 This->stateBlock->streamOffset[0] = 0;
5311 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5312 This->stateBlock->streamIsUP = TRUE;
5313 This->stateBlock->loadBaseVertexIndex = 0;
5315 /* TODO: Only mark dirty if drawing from a different UP address */
5316 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5318 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5319 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5321 /* MSDN specifies stream zero settings must be set to NULL */
5322 This->stateBlock->streamStride[0] = 0;
5323 This->stateBlock->streamSource[0] = NULL;
5325 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5326 * the new stream sources or use UP drawing again
5331 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5332 UINT MinVertexIndex, UINT NumVertices,
5333 UINT PrimitiveCount, CONST void* pIndexData,
5334 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5335 UINT VertexStreamZeroStride) {
5337 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5338 IWineD3DVertexBuffer *vb;
5339 IWineD3DIndexBuffer *ib;
5341 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5342 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5343 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5344 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5346 if(!This->stateBlock->vertexDecl) {
5347 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5348 return WINED3DERR_INVALIDCALL;
5351 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5357 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5358 vb = This->stateBlock->streamSource[0];
5359 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5360 if(vb) IWineD3DVertexBuffer_Release(vb);
5361 This->stateBlock->streamIsUP = TRUE;
5362 This->stateBlock->streamOffset[0] = 0;
5363 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5365 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5366 This->stateBlock->baseVertexIndex = 0;
5367 This->stateBlock->loadBaseVertexIndex = 0;
5368 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5369 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5370 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5372 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5374 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5375 This->stateBlock->streamSource[0] = NULL;
5376 This->stateBlock->streamStride[0] = 0;
5377 ib = This->stateBlock->pIndexData;
5379 IWineD3DIndexBuffer_Release(ib);
5380 This->stateBlock->pIndexData = NULL;
5382 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5383 * SetStreamSource to specify a vertex buffer
5389 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5390 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5391 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5393 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5395 /* Mark the state dirty until we have nicer tracking
5396 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5400 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5401 This->stateBlock->baseVertexIndex = 0;
5402 This->up_strided = DrawPrimStrideData;
5403 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5404 This->up_strided = NULL;
5408 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5409 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5410 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5411 WINED3DFORMAT IndexDataFormat)
5413 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5414 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5416 /* Mark the state dirty until we have nicer tracking
5417 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5420 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5421 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5422 This->stateBlock->streamIsUP = TRUE;
5423 This->stateBlock->baseVertexIndex = 0;
5424 This->up_strided = DrawPrimStrideData;
5425 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5426 This->up_strided = NULL;
5430 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5431 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5432 * not callable by the app directly no parameter validation checks are needed here.
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5435 WINED3DLOCKED_BOX src;
5436 WINED3DLOCKED_BOX dst;
5438 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5440 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5441 * dirtification to improve loading performance.
5443 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5444 if(FAILED(hr)) return hr;
5445 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5447 IWineD3DVolume_UnlockBox(pSourceVolume);
5451 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5453 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5455 IWineD3DVolume_UnlockBox(pSourceVolume);
5457 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5462 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5463 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5464 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5465 HRESULT hr = WINED3D_OK;
5466 WINED3DRESOURCETYPE sourceType;
5467 WINED3DRESOURCETYPE destinationType;
5470 /* TODO: think about moving the code into IWineD3DBaseTexture */
5472 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5474 /* verify that the source and destination textures aren't NULL */
5475 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5476 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5477 This, pSourceTexture, pDestinationTexture);
5478 hr = WINED3DERR_INVALIDCALL;
5481 if (pSourceTexture == pDestinationTexture) {
5482 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5483 This, pSourceTexture, pDestinationTexture);
5484 hr = WINED3DERR_INVALIDCALL;
5486 /* Verify that the source and destination textures are the same type */
5487 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5488 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5490 if (sourceType != destinationType) {
5491 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5493 hr = WINED3DERR_INVALIDCALL;
5496 /* check that both textures have the identical numbers of levels */
5497 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5498 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5499 hr = WINED3DERR_INVALIDCALL;
5502 if (WINED3D_OK == hr) {
5504 /* Make sure that the destination texture is loaded */
5505 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5507 /* Update every surface level of the texture */
5508 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5510 switch (sourceType) {
5511 case WINED3DRTYPE_TEXTURE:
5513 IWineD3DSurface *srcSurface;
5514 IWineD3DSurface *destSurface;
5516 for (i = 0 ; i < levels ; ++i) {
5517 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5518 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5519 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5520 IWineD3DSurface_Release(srcSurface);
5521 IWineD3DSurface_Release(destSurface);
5522 if (WINED3D_OK != hr) {
5523 WARN("(%p) : Call to update surface failed\n", This);
5529 case WINED3DRTYPE_CUBETEXTURE:
5531 IWineD3DSurface *srcSurface;
5532 IWineD3DSurface *destSurface;
5533 WINED3DCUBEMAP_FACES faceType;
5535 for (i = 0 ; i < levels ; ++i) {
5536 /* Update each cube face */
5537 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5538 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5539 if (WINED3D_OK != hr) {
5540 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5542 TRACE("Got srcSurface %p\n", srcSurface);
5544 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5545 if (WINED3D_OK != hr) {
5546 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5548 TRACE("Got desrSurface %p\n", destSurface);
5550 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5551 IWineD3DSurface_Release(srcSurface);
5552 IWineD3DSurface_Release(destSurface);
5553 if (WINED3D_OK != hr) {
5554 WARN("(%p) : Call to update surface failed\n", This);
5562 case WINED3DRTYPE_VOLUMETEXTURE:
5564 IWineD3DVolume *srcVolume = NULL;
5565 IWineD3DVolume *destVolume = NULL;
5567 for (i = 0 ; i < levels ; ++i) {
5568 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5569 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5570 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5571 IWineD3DVolume_Release(srcVolume);
5572 IWineD3DVolume_Release(destVolume);
5573 if (WINED3D_OK != hr) {
5574 WARN("(%p) : Call to update volume failed\n", This);
5582 FIXME("(%p) : Unsupported source and destination type\n", This);
5583 hr = WINED3DERR_INVALIDCALL;
5590 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5591 IWineD3DSwapChain *swapChain;
5593 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5594 if(hr == WINED3D_OK) {
5595 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5596 IWineD3DSwapChain_Release(swapChain);
5601 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5603 IWineD3DBaseTextureImpl *texture;
5604 const struct GlPixelFormatDesc *gl_info;
5607 TRACE("(%p) : %p\n", This, pNumPasses);
5609 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5610 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5611 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5612 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5614 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5615 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5616 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5619 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5620 if(!texture) continue;
5621 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5622 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5624 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5625 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5628 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5629 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5632 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5633 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5634 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5639 /* return a sensible default */
5642 TRACE("returning D3D_OK\n");
5646 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5650 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5651 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5652 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5653 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5658 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5662 PALETTEENTRY **palettes;
5664 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5666 if (PaletteNumber >= MAX_PALETTES) {
5667 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5668 return WINED3DERR_INVALIDCALL;
5671 if (PaletteNumber >= This->NumberOfPalettes) {
5672 NewSize = This->NumberOfPalettes;
5675 } while(PaletteNumber >= NewSize);
5676 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5678 ERR("Out of memory!\n");
5679 return E_OUTOFMEMORY;
5681 This->palettes = palettes;
5682 This->NumberOfPalettes = NewSize;
5685 if (!This->palettes[PaletteNumber]) {
5686 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5687 if (!This->palettes[PaletteNumber]) {
5688 ERR("Out of memory!\n");
5689 return E_OUTOFMEMORY;
5693 for (j = 0; j < 256; ++j) {
5694 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5695 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5696 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5697 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5699 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5700 TRACE("(%p) : returning\n", This);
5704 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5707 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5708 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5709 /* What happens in such situation isn't documented; Native seems to silently abort
5710 on such conditions. Return Invalid Call. */
5711 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5712 return WINED3DERR_INVALIDCALL;
5714 for (j = 0; j < 256; ++j) {
5715 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5716 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5717 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5718 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5720 TRACE("(%p) : returning\n", This);
5724 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5725 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5726 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5727 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5728 (tested with reference rasterizer). Return Invalid Call. */
5729 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5730 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5731 return WINED3DERR_INVALIDCALL;
5733 /*TODO: stateblocks */
5734 if (This->currentPalette != PaletteNumber) {
5735 This->currentPalette = PaletteNumber;
5736 dirtify_p8_texture_samplers(This);
5738 TRACE("(%p) : returning\n", This);
5742 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 if (PaletteNumber == NULL) {
5745 WARN("(%p) : returning Invalid Call\n", This);
5746 return WINED3DERR_INVALIDCALL;
5748 /*TODO: stateblocks */
5749 *PaletteNumber = This->currentPalette;
5750 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5754 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5759 FIXME("(%p) : stub\n", This);
5763 This->softwareVertexProcessing = bSoftware;
5768 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5773 FIXME("(%p) : stub\n", This);
5776 return This->softwareVertexProcessing;
5780 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 IWineD3DSwapChain *swapChain;
5785 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5787 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5788 if(hr == WINED3D_OK){
5789 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5790 IWineD3DSwapChain_Release(swapChain);
5792 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5798 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5801 if(nSegments != 0.0f) {
5804 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5811 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5812 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5816 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5822 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5823 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5824 /** TODO: remove casts to IWineD3DSurfaceImpl
5825 * NOTE: move code to surface to accomplish this
5826 ****************************************/
5827 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5828 int srcWidth, srcHeight;
5829 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5830 WINED3DFORMAT destFormat, srcFormat;
5832 int srcLeft, destLeft, destTop;
5833 WINED3DPOOL srcPool, destPool;
5835 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5836 glDescriptor *glDescription = NULL;
5840 CONVERT_TYPES convert = NO_CONVERSION;
5842 WINED3DSURFACE_DESC winedesc;
5844 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5845 memset(&winedesc, 0, sizeof(winedesc));
5846 winedesc.Width = &srcSurfaceWidth;
5847 winedesc.Height = &srcSurfaceHeight;
5848 winedesc.Pool = &srcPool;
5849 winedesc.Format = &srcFormat;
5851 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5853 winedesc.Width = &destSurfaceWidth;
5854 winedesc.Height = &destSurfaceHeight;
5855 winedesc.Pool = &destPool;
5856 winedesc.Format = &destFormat;
5857 winedesc.Size = &destSize;
5859 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5861 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5862 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5863 return WINED3DERR_INVALIDCALL;
5866 /* This call loads the opengl surface directly, instead of copying the surface to the
5867 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5868 * copy in sysmem and use regular surface loading.
5870 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5871 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5872 if(convert != NO_CONVERSION) {
5873 return IWineD3DSurface_BltFast(pDestinationSurface,
5874 pDestPoint ? pDestPoint->x : 0,
5875 pDestPoint ? pDestPoint->y : 0,
5876 pSourceSurface, pSourceRect, 0);
5879 if (destFormat == WINED3DFMT_UNKNOWN) {
5880 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5881 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5883 /* Get the update surface description */
5884 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5887 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5889 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5891 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5892 checkGLcall("glActiveTextureARB");
5896 /* Make sure the surface is loaded and up to date */
5897 IWineD3DSurface_PreLoad(pDestinationSurface);
5898 IWineD3DSurface_BindTexture(pDestinationSurface);
5900 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5902 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5903 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5904 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5905 srcLeft = pSourceRect ? pSourceRect->left : 0;
5906 destLeft = pDestPoint ? pDestPoint->x : 0;
5907 destTop = pDestPoint ? pDestPoint->y : 0;
5910 /* This function doesn't support compressed textures
5911 the pitch is just bytesPerPixel * width */
5912 if(srcWidth != srcSurfaceWidth || srcLeft ){
5913 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5914 offset += srcLeft * pSrcSurface->bytesPerPixel;
5915 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5917 /* TODO DXT formats */
5919 if(pSourceRect != NULL && pSourceRect->top != 0){
5920 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5922 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5923 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5924 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5927 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5929 /* need to lock the surface to get the data */
5930 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5935 /* TODO: Cube and volume support */
5937 /* not a whole row so we have to do it a line at a time */
5940 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5941 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5943 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5945 glTexSubImage2D(glDescription->target
5946 ,glDescription->level
5951 ,glDescription->glFormat
5952 ,glDescription->glType
5953 ,data /* could be quicker using */
5958 } else { /* Full width, so just write out the whole texture */
5959 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5961 if (WINED3DFMT_DXT1 == destFormat ||
5962 WINED3DFMT_DXT2 == destFormat ||
5963 WINED3DFMT_DXT3 == destFormat ||
5964 WINED3DFMT_DXT4 == destFormat ||
5965 WINED3DFMT_DXT5 == destFormat) {
5966 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5967 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5968 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5969 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5970 } if (destFormat != srcFormat) {
5971 FIXME("Updating mixed format compressed texture is not curretly support\n");
5973 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5974 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5977 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5982 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5983 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5986 checkGLcall("glTexSubImage2D");
5990 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5991 sampler = This->rev_tex_unit_map[0];
5992 if (sampler != -1) {
5993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5999 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6001 struct WineD3DRectPatch *patch;
6005 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6007 if(!(Handle || pRectPatchInfo)) {
6008 /* TODO: Write a test for the return value, thus the FIXME */
6009 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6010 return WINED3DERR_INVALIDCALL;
6014 i = PATCHMAP_HASHFUNC(Handle);
6016 LIST_FOR_EACH(e, &This->patches[i]) {
6017 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6018 if(patch->Handle == Handle) {
6025 TRACE("Patch does not exist. Creating a new one\n");
6026 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6027 patch->Handle = Handle;
6028 list_add_head(&This->patches[i], &patch->entry);
6030 TRACE("Found existing patch %p\n", patch);
6033 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6034 * attributes we have to tesselate, read back, and draw. This needs a patch
6035 * management structure instance. Create one.
6037 * A possible improvement is to check if a vertex shader is used, and if not directly
6040 FIXME("Drawing an uncached patch. This is slow\n");
6041 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6044 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6045 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6046 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6048 TRACE("Tesselation density or patch info changed, retesselating\n");
6050 if(pRectPatchInfo) {
6051 patch->RectPatchInfo = *pRectPatchInfo;
6053 patch->numSegs[0] = pNumSegs[0];
6054 patch->numSegs[1] = pNumSegs[1];
6055 patch->numSegs[2] = pNumSegs[2];
6056 patch->numSegs[3] = pNumSegs[3];
6058 hr = tesselate_rectpatch(This, patch);
6060 WARN("Patch tesselation failed\n");
6062 /* Do not release the handle to store the params of the patch */
6064 HeapFree(GetProcessHeap(), 0, patch);
6070 This->currentPatch = patch;
6071 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6072 This->currentPatch = NULL;
6074 /* Destroy uncached patches */
6076 HeapFree(GetProcessHeap(), 0, patch->mem);
6077 HeapFree(GetProcessHeap(), 0, patch);
6082 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6083 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6084 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6085 FIXME("(%p) : Stub\n", This);
6089 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6090 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6092 struct WineD3DRectPatch *patch;
6094 TRACE("(%p) Handle(%d)\n", This, Handle);
6096 i = PATCHMAP_HASHFUNC(Handle);
6097 LIST_FOR_EACH(e, &This->patches[i]) {
6098 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6099 if(patch->Handle == Handle) {
6100 TRACE("Deleting patch %p\n", patch);
6101 list_remove(&patch->entry);
6102 HeapFree(GetProcessHeap(), 0, patch->mem);
6103 HeapFree(GetProcessHeap(), 0, patch);
6108 /* TODO: Write a test for the return value */
6109 FIXME("Attempt to destroy nonexistent patch\n");
6110 return WINED3DERR_INVALIDCALL;
6113 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6115 IWineD3DSwapChain *swapchain;
6117 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6118 if (SUCCEEDED(hr)) {
6119 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6126 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6128 IWineD3DSwapChain *swapchain;
6130 swapchain = get_swapchain(surface);
6134 TRACE("Surface %p is onscreen\n", surface);
6136 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6138 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6139 buffer = surface_get_gl_buffer(surface, swapchain);
6140 glDrawBuffer(buffer);
6141 checkGLcall("glDrawBuffer()");
6143 TRACE("Surface %p is offscreen\n", surface);
6145 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6147 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6148 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6149 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6150 checkGLcall("glFramebufferRenderbufferEXT");
6154 glEnable(GL_SCISSOR_TEST);
6156 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6158 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6159 rect->x2 - rect->x1, rect->y2 - rect->y1);
6161 checkGLcall("glScissor");
6162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6164 glDisable(GL_SCISSOR_TEST);
6166 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6168 glDisable(GL_BLEND);
6169 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6171 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6172 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6174 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6175 glClear(GL_COLOR_BUFFER_BIT);
6176 checkGLcall("glClear");
6178 if (This->activeContext->current_fbo) {
6179 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6181 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6182 checkGLcall("glBindFramebuffer()");
6185 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6186 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6187 glDrawBuffer(GL_BACK);
6188 checkGLcall("glDrawBuffer()");
6194 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6195 unsigned int r, g, b, a;
6198 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6199 destfmt == WINED3DFMT_R8G8B8)
6202 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6204 a = (color & 0xff000000) >> 24;
6205 r = (color & 0x00ff0000) >> 16;
6206 g = (color & 0x0000ff00) >> 8;
6207 b = (color & 0x000000ff) >> 0;
6211 case WINED3DFMT_R5G6B5:
6212 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6219 TRACE("Returning %08x\n", ret);
6222 case WINED3DFMT_X1R5G5B5:
6223 case WINED3DFMT_A1R5G5B5:
6232 TRACE("Returning %08x\n", ret);
6236 TRACE("Returning %08x\n", a);
6239 case WINED3DFMT_X4R4G4B4:
6240 case WINED3DFMT_A4R4G4B4:
6249 TRACE("Returning %08x\n", ret);
6252 case WINED3DFMT_R3G3B2:
6259 TRACE("Returning %08x\n", ret);
6262 case WINED3DFMT_X8B8G8R8:
6263 case WINED3DFMT_A8B8G8R8:
6268 TRACE("Returning %08x\n", ret);
6271 case WINED3DFMT_A2R10G10B10:
6273 r = (r * 1024) / 256;
6274 g = (g * 1024) / 256;
6275 b = (b * 1024) / 256;
6280 TRACE("Returning %08x\n", ret);
6283 case WINED3DFMT_A2B10G10R10:
6285 r = (r * 1024) / 256;
6286 g = (g * 1024) / 256;
6287 b = (b * 1024) / 256;
6292 TRACE("Returning %08x\n", ret);
6296 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6301 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6303 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6305 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6307 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6308 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6309 return WINED3DERR_INVALIDCALL;
6312 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6313 color_fill_fbo(iface, pSurface, pRect, color);
6316 /* Just forward this to the DirectDraw blitting engine */
6317 memset(&BltFx, 0, sizeof(BltFx));
6318 BltFx.dwSize = sizeof(BltFx);
6319 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6320 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6321 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6325 /* rendertarget and depth stencil functions */
6326 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6327 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6329 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6330 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6331 return WINED3DERR_INVALIDCALL;
6334 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6335 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6336 /* Note inc ref on returned surface */
6337 if(*ppRenderTarget != NULL)
6338 IWineD3DSurface_AddRef(*ppRenderTarget);
6342 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6343 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6344 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6345 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6346 IWineD3DSwapChainImpl *Swapchain;
6349 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6351 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6352 if(hr != WINED3D_OK) {
6353 ERR("Can't get the swapchain\n");
6357 /* Make sure to release the swapchain */
6358 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6360 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6361 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6362 return WINED3DERR_INVALIDCALL;
6364 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6365 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6366 return WINED3DERR_INVALIDCALL;
6369 if(Swapchain->frontBuffer != Front) {
6370 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6372 if(Swapchain->frontBuffer)
6373 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6374 Swapchain->frontBuffer = Front;
6376 if(Swapchain->frontBuffer) {
6377 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6381 if(Back && !Swapchain->backBuffer) {
6382 /* We need memory for the back buffer array - only one back buffer this way */
6383 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6384 if(!Swapchain->backBuffer) {
6385 ERR("Out of memory\n");
6386 return E_OUTOFMEMORY;
6390 if(Swapchain->backBuffer[0] != Back) {
6391 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6393 /* What to do about the context here in the case of multithreading? Not sure.
6394 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6397 if(!Swapchain->backBuffer[0]) {
6398 /* GL was told to draw to the front buffer at creation,
6401 glDrawBuffer(GL_BACK);
6402 checkGLcall("glDrawBuffer(GL_BACK)");
6403 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6404 Swapchain->presentParms.BackBufferCount = 1;
6406 /* That makes problems - disable for now */
6407 /* glDrawBuffer(GL_FRONT); */
6408 checkGLcall("glDrawBuffer(GL_FRONT)");
6409 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6410 Swapchain->presentParms.BackBufferCount = 0;
6414 if(Swapchain->backBuffer[0])
6415 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6416 Swapchain->backBuffer[0] = Back;
6418 if(Swapchain->backBuffer[0]) {
6419 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6421 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6422 Swapchain->backBuffer = NULL;
6430 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6431 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6432 *ppZStencilSurface = This->stencilBufferTarget;
6433 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6435 if(*ppZStencilSurface != NULL) {
6436 /* Note inc ref on returned surface */
6437 IWineD3DSurface_AddRef(*ppZStencilSurface);
6440 return WINED3DERR_NOTFOUND;
6444 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6445 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6448 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6449 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6451 POINT offset = {0, 0};
6453 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6454 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6455 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6456 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6459 case WINED3DTEXF_LINEAR:
6460 gl_filter = GL_LINEAR;
6464 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6465 case WINED3DTEXF_NONE:
6466 case WINED3DTEXF_POINT:
6467 gl_filter = GL_NEAREST;
6471 /* Attach src surface to src fbo */
6472 src_swapchain = get_swapchain(src_surface);
6473 if (src_swapchain) {
6474 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6476 TRACE("Source surface %p is onscreen\n", src_surface);
6477 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6478 /* Make sure the drawable is up to date. In the offscreen case
6479 * attach_surface_fbo() implicitly takes care of this. */
6480 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6482 if(buffer == GL_FRONT) {
6485 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6486 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6487 h = windowsize.bottom - windowsize.top;
6488 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6489 src_rect->y1 = offset.y + h - src_rect->y1;
6490 src_rect->y2 = offset.y + h - src_rect->y2;
6492 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6493 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6497 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6498 glReadBuffer(buffer);
6499 checkGLcall("glReadBuffer()");
6501 TRACE("Source surface %p is offscreen\n", src_surface);
6503 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6504 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6505 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6506 checkGLcall("glReadBuffer()");
6507 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6508 checkGLcall("glFramebufferRenderbufferEXT");
6512 /* Attach dst surface to dst fbo */
6513 dst_swapchain = get_swapchain(dst_surface);
6514 if (dst_swapchain) {
6515 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6517 TRACE("Destination surface %p is onscreen\n", dst_surface);
6518 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6519 /* Make sure the drawable is up to date. In the offscreen case
6520 * attach_surface_fbo() implicitly takes care of this. */
6521 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6523 if(buffer == GL_FRONT) {
6526 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6527 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6528 h = windowsize.bottom - windowsize.top;
6529 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6530 dst_rect->y1 = offset.y + h - dst_rect->y1;
6531 dst_rect->y2 = offset.y + h - dst_rect->y2;
6533 /* Screen coords = window coords, surface height = window height */
6534 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6535 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6539 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6540 glDrawBuffer(buffer);
6541 checkGLcall("glDrawBuffer()");
6543 TRACE("Destination surface %p is offscreen\n", dst_surface);
6545 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6546 if(!src_swapchain) {
6547 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6551 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6552 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6553 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6554 checkGLcall("glDrawBuffer()");
6555 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6556 checkGLcall("glFramebufferRenderbufferEXT");
6558 glDisable(GL_SCISSOR_TEST);
6559 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6562 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6563 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6564 checkGLcall("glBlitFramebuffer()");
6566 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6567 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6568 checkGLcall("glBlitFramebuffer()");
6571 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6573 if (This->activeContext->current_fbo) {
6574 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6576 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6577 checkGLcall("glBindFramebuffer()");
6580 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6581 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6582 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6583 glDrawBuffer(GL_BACK);
6584 checkGLcall("glDrawBuffer()");
6589 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6591 WINED3DVIEWPORT viewport;
6593 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6595 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6596 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6597 This, RenderTargetIndex, GL_LIMITS(buffers));
6598 return WINED3DERR_INVALIDCALL;
6601 /* MSDN says that null disables the render target
6602 but a device must always be associated with a render target
6603 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6605 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6606 FIXME("Trying to set render target 0 to NULL\n");
6607 return WINED3DERR_INVALIDCALL;
6609 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6610 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);
6611 return WINED3DERR_INVALIDCALL;
6614 /* If we are trying to set what we already have, don't bother */
6615 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6616 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6619 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6620 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6621 This->render_targets[RenderTargetIndex] = pRenderTarget;
6623 /* Render target 0 is special */
6624 if(RenderTargetIndex == 0) {
6625 /* Finally, reset the viewport as the MSDN states. */
6626 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6627 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6630 viewport.MaxZ = 1.0f;
6631 viewport.MinZ = 0.0f;
6632 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6633 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6634 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6636 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6641 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6643 HRESULT hr = WINED3D_OK;
6644 IWineD3DSurface *tmp;
6646 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6648 if (pNewZStencil == This->stencilBufferTarget) {
6649 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6651 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6652 * depending on the renter target implementation being used.
6653 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6654 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6655 * stencil buffer and incur an extra memory overhead
6656 ******************************************************/
6658 if (This->stencilBufferTarget) {
6659 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6660 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6661 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6663 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6664 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6665 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6669 tmp = This->stencilBufferTarget;
6670 This->stencilBufferTarget = pNewZStencil;
6671 /* should we be calling the parent or the wined3d surface? */
6672 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6673 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6676 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6677 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6678 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6679 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6687 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6688 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6690 /* TODO: the use of Impl is deprecated. */
6691 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6692 WINED3DLOCKED_RECT lockedRect;
6694 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6696 /* some basic validation checks */
6697 if(This->cursorTexture) {
6698 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6700 glDeleteTextures(1, &This->cursorTexture);
6702 This->cursorTexture = 0;
6705 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6706 This->haveHardwareCursor = TRUE;
6708 This->haveHardwareCursor = FALSE;
6711 WINED3DLOCKED_RECT rect;
6713 /* MSDN: Cursor must be A8R8G8B8 */
6714 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6715 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6716 return WINED3DERR_INVALIDCALL;
6719 /* MSDN: Cursor must be smaller than the display mode */
6720 if(pSur->currentDesc.Width > This->ddraw_width ||
6721 pSur->currentDesc.Height > This->ddraw_height) {
6722 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);
6723 return WINED3DERR_INVALIDCALL;
6726 if (!This->haveHardwareCursor) {
6727 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6729 /* Do not store the surface's pointer because the application may
6730 * release it after setting the cursor image. Windows doesn't
6731 * addref the set surface, so we can't do this either without
6732 * creating circular refcount dependencies. Copy out the gl texture
6735 This->cursorWidth = pSur->currentDesc.Width;
6736 This->cursorHeight = pSur->currentDesc.Height;
6737 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6739 const struct GlPixelFormatDesc *glDesc;
6740 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6741 char *mem, *bits = (char *)rect.pBits;
6742 GLint intfmt = glDesc->glInternal;
6743 GLint format = glDesc->glFormat;
6744 GLint type = glDesc->glType;
6745 INT height = This->cursorHeight;
6746 INT width = This->cursorWidth;
6747 INT bpp = tableEntry->bpp;
6750 /* Reformat the texture memory (pitch and width can be
6752 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6753 for(i = 0; i < height; i++)
6754 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6755 IWineD3DSurface_UnlockRect(pCursorBitmap);
6758 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6759 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6760 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6763 /* Make sure that a proper texture unit is selected */
6764 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6765 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6766 checkGLcall("glActiveTextureARB");
6768 sampler = This->rev_tex_unit_map[0];
6769 if (sampler != -1) {
6770 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6772 /* Create a new cursor texture */
6773 glGenTextures(1, &This->cursorTexture);
6774 checkGLcall("glGenTextures");
6775 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6776 checkGLcall("glBindTexture");
6777 /* Copy the bitmap memory into the cursor texture */
6778 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6779 HeapFree(GetProcessHeap(), 0, mem);
6780 checkGLcall("glTexImage2D");
6782 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6783 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6784 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6791 FIXME("A cursor texture was not returned.\n");
6792 This->cursorTexture = 0;
6797 /* Draw a hardware cursor */
6798 ICONINFO cursorInfo;
6800 /* Create and clear maskBits because it is not needed for
6801 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6803 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6804 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6805 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6806 WINED3DLOCK_NO_DIRTY_UPDATE |
6807 WINED3DLOCK_READONLY
6809 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6810 pSur->currentDesc.Height);
6812 cursorInfo.fIcon = FALSE;
6813 cursorInfo.xHotspot = XHotSpot;
6814 cursorInfo.yHotspot = YHotSpot;
6815 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6816 pSur->currentDesc.Height, 1,
6818 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6819 pSur->currentDesc.Height, 1,
6820 32, lockedRect.pBits);
6821 IWineD3DSurface_UnlockRect(pCursorBitmap);
6822 /* Create our cursor and clean up. */
6823 cursor = CreateIconIndirect(&cursorInfo);
6825 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6826 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6827 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6828 This->hardwareCursor = cursor;
6829 HeapFree(GetProcessHeap(), 0, maskBits);
6833 This->xHotSpot = XHotSpot;
6834 This->yHotSpot = YHotSpot;
6838 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6840 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6842 This->xScreenSpace = XScreenSpace;
6843 This->yScreenSpace = YScreenSpace;
6849 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6850 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6851 BOOL oldVisible = This->bCursorVisible;
6854 TRACE("(%p) : visible(%d)\n", This, bShow);
6857 * When ShowCursor is first called it should make the cursor appear at the OS's last
6858 * known cursor position. Because of this, some applications just repetitively call
6859 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6862 This->xScreenSpace = pt.x;
6863 This->yScreenSpace = pt.y;
6865 if (This->haveHardwareCursor) {
6866 This->bCursorVisible = bShow;
6868 SetCursor(This->hardwareCursor);
6874 if (This->cursorTexture)
6875 This->bCursorVisible = bShow;
6881 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6882 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6883 IWineD3DResourceImpl *resource;
6884 TRACE("(%p) : state (%u)\n", This, This->state);
6886 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6887 switch (This->state) {
6890 case WINED3DERR_DEVICELOST:
6892 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6893 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6894 return WINED3DERR_DEVICENOTRESET;
6896 return WINED3DERR_DEVICELOST;
6898 case WINED3DERR_DRIVERINTERNALERROR:
6899 return WINED3DERR_DRIVERINTERNALERROR;
6903 return WINED3DERR_DRIVERINTERNALERROR;
6907 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6909 /** FIXME: Resource tracking needs to be done,
6910 * The closes we can do to this is set the priorities of all managed textures low
6911 * and then reset them.
6912 ***********************************************************/
6913 FIXME("(%p) : stub\n", This);
6917 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6919 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6921 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6922 if(surface->Flags & SFLAG_DIBSECTION) {
6923 /* Release the DC */
6924 SelectObject(surface->hDC, surface->dib.holdbitmap);
6925 DeleteDC(surface->hDC);
6926 /* Release the DIB section */
6927 DeleteObject(surface->dib.DIBsection);
6928 surface->dib.bitmap_data = NULL;
6929 surface->resource.allocatedMemory = NULL;
6930 surface->Flags &= ~SFLAG_DIBSECTION;
6932 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6933 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6934 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6935 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6936 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6937 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6939 surface->pow2Width = surface->pow2Height = 1;
6940 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6941 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6943 surface->glRect.left = 0;
6944 surface->glRect.top = 0;
6945 surface->glRect.right = surface->pow2Width;
6946 surface->glRect.bottom = surface->pow2Height;
6948 if(surface->glDescription.textureName) {
6949 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6951 glDeleteTextures(1, &surface->glDescription.textureName);
6953 surface->glDescription.textureName = 0;
6954 surface->Flags &= ~SFLAG_CLIENT;
6956 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6957 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6958 surface->Flags |= SFLAG_NONPOW2;
6960 surface->Flags &= ~SFLAG_NONPOW2;
6962 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6963 surface->resource.allocatedMemory = NULL;
6964 surface->resource.heapMemory = NULL;
6965 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6966 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6967 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6968 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6970 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6974 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6975 TRACE("Unloading resource %p\n", resource);
6976 IWineD3DResource_UnLoad(resource);
6977 IWineD3DResource_Release(resource);
6981 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6984 WINED3DDISPLAYMODE m;
6987 /* All Windowed modes are supported, as is leaving the current mode */
6988 if(pp->Windowed) return TRUE;
6989 if(!pp->BackBufferWidth) return TRUE;
6990 if(!pp->BackBufferHeight) return TRUE;
6992 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6993 for(i = 0; i < count; i++) {
6994 memset(&m, 0, sizeof(m));
6995 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
6997 ERR("EnumAdapterModes failed\n");
6999 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7000 /* Mode found, it is supported */
7004 /* Mode not found -> not supported */
7008 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7010 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7012 IWineD3DBaseShaderImpl *shader;
7014 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7015 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7016 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7020 if(This->depth_blt_texture) {
7021 glDeleteTextures(1, &This->depth_blt_texture);
7022 This->depth_blt_texture = 0;
7024 if (This->depth_blt_rb) {
7025 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7026 This->depth_blt_rb = 0;
7027 This->depth_blt_rb_w = 0;
7028 This->depth_blt_rb_h = 0;
7032 This->blitter->free_private(iface);
7033 This->frag_pipe->free_private(iface);
7034 This->shader_backend->shader_free_private(iface);
7037 for (i = 0; i < GL_LIMITS(textures); i++) {
7038 /* Textures are recreated below */
7039 glDeleteTextures(1, &This->dummyTextureName[i]);
7040 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7041 This->dummyTextureName[i] = 0;
7045 while(This->numContexts) {
7046 DestroyContext(This, This->contexts[0]);
7048 This->activeContext = NULL;
7049 HeapFree(GetProcessHeap(), 0, swapchain->context);
7050 swapchain->context = NULL;
7051 swapchain->num_contexts = 0;
7054 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7056 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7058 IWineD3DSurfaceImpl *target;
7060 /* Recreate the primary swapchain's context */
7061 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7062 if(swapchain->backBuffer) {
7063 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7065 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7067 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7068 &swapchain->presentParms);
7069 swapchain->num_contexts = 1;
7070 This->activeContext = swapchain->context[0];
7072 create_dummy_textures(This);
7074 hr = This->shader_backend->shader_alloc_private(iface);
7076 ERR("Failed to recreate shader private data\n");
7079 hr = This->frag_pipe->alloc_private(iface);
7081 TRACE("Fragment pipeline private data couldn't be allocated\n");
7084 hr = This->blitter->alloc_private(iface);
7086 TRACE("Blitter private data couldn't be allocated\n");
7093 This->blitter->free_private(iface);
7094 This->frag_pipe->free_private(iface);
7095 This->shader_backend->shader_free_private(iface);
7099 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7101 IWineD3DSwapChainImpl *swapchain;
7103 BOOL DisplayModeChanged = FALSE;
7104 WINED3DDISPLAYMODE mode;
7105 TRACE("(%p)\n", This);
7107 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7109 ERR("Failed to get the first implicit swapchain\n");
7113 if(!is_display_mode_supported(This, pPresentationParameters)) {
7114 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7115 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7116 pPresentationParameters->BackBufferHeight);
7117 return WINED3DERR_INVALIDCALL;
7120 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7121 * on an existing gl context, so there's no real need for recreation.
7123 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7125 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7127 TRACE("New params:\n");
7128 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7129 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7130 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7131 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7132 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7133 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7134 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7135 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7136 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7137 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7138 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7139 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7140 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7142 /* No special treatment of these parameters. Just store them */
7143 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7144 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7145 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7146 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7148 /* What to do about these? */
7149 if(pPresentationParameters->BackBufferCount != 0 &&
7150 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7151 ERR("Cannot change the back buffer count yet\n");
7153 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7154 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7155 ERR("Cannot change the back buffer format yet\n");
7157 if(pPresentationParameters->hDeviceWindow != NULL &&
7158 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7159 ERR("Cannot change the device window yet\n");
7161 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7162 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7163 return WINED3DERR_INVALIDCALL;
7166 /* Reset the depth stencil */
7167 if (pPresentationParameters->EnableAutoDepthStencil)
7168 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7170 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7172 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7174 if(pPresentationParameters->Windowed) {
7175 mode.Width = swapchain->orig_width;
7176 mode.Height = swapchain->orig_height;
7177 mode.RefreshRate = 0;
7178 mode.Format = swapchain->presentParms.BackBufferFormat;
7180 mode.Width = pPresentationParameters->BackBufferWidth;
7181 mode.Height = pPresentationParameters->BackBufferHeight;
7182 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7183 mode.Format = swapchain->presentParms.BackBufferFormat;
7186 /* Should Width == 800 && Height == 0 set 800x600? */
7187 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7188 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7189 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7196 vp.Width = pPresentationParameters->BackBufferWidth;
7197 vp.Height = pPresentationParameters->BackBufferHeight;
7201 if(!pPresentationParameters->Windowed) {
7202 DisplayModeChanged = TRUE;
7204 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7205 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7207 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7208 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7209 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7211 if(This->auto_depth_stencil_buffer) {
7212 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7216 /* Now set the new viewport */
7217 IWineD3DDevice_SetViewport(iface, &vp);
7220 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7221 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7222 DisplayModeChanged) {
7224 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7226 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7227 if(swapchain->presentParms.Windowed) {
7228 /* switch from windowed to fs */
7229 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7230 pPresentationParameters->BackBufferWidth,
7231 pPresentationParameters->BackBufferHeight);
7233 /* Fullscreen -> fullscreen mode change */
7234 MoveWindow(swapchain->win_handle, 0, 0,
7235 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7238 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7239 /* Fullscreen -> windowed switch */
7240 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7242 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7243 } else if(!pPresentationParameters->Windowed) {
7244 DWORD style = This->style, exStyle = This->exStyle;
7245 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7246 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7247 * Reset to clear up their mess. Guild Wars also loses the device during that.
7251 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7252 pPresentationParameters->BackBufferWidth,
7253 pPresentationParameters->BackBufferHeight);
7254 This->style = style;
7255 This->exStyle = exStyle;
7258 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7260 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7263 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7264 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7266 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7272 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7273 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7274 /** FIXME: always true at the moment **/
7275 if(!bEnableDialogs) {
7276 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7282 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7283 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7284 TRACE("(%p) : pParameters %p\n", This, pParameters);
7286 *pParameters = This->createParms;
7290 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7291 IWineD3DSwapChain *swapchain;
7293 TRACE("Relaying to swapchain\n");
7295 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7296 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7297 IWineD3DSwapChain_Release(swapchain);
7302 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7303 IWineD3DSwapChain *swapchain;
7305 TRACE("Relaying to swapchain\n");
7307 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7308 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7309 IWineD3DSwapChain_Release(swapchain);
7315 /** ********************************************************
7316 * Notification functions
7317 ** ********************************************************/
7318 /** This function must be called in the release of a resource when ref == 0,
7319 * the contents of resource must still be correct,
7320 * any handles to other resource held by the caller must be closed
7321 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7322 *****************************************************/
7323 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7324 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7326 TRACE("(%p) : Adding Resource %p\n", This, resource);
7327 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7330 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7333 TRACE("(%p) : Removing resource %p\n", This, resource);
7335 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7339 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7341 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7344 TRACE("(%p) : resource %p\n", This, resource);
7346 context_resource_released(iface, resource, type);
7349 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7350 case WINED3DRTYPE_SURFACE: {
7353 /* Cleanup any FBO attachments if d3d is enabled */
7354 if(This->d3d_initialized) {
7355 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7356 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7358 TRACE("Last active render target destroyed\n");
7359 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7360 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7361 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7362 * and the lastActiveRenderTarget member shouldn't matter
7365 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7366 TRACE("Activating primary back buffer\n");
7367 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7368 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7369 /* Single buffering environment */
7370 TRACE("Activating primary front buffer\n");
7371 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7373 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7374 /* Implicit render target destroyed, that means the device is being destroyed
7375 * whatever we set here, it shouldn't matter
7377 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7380 /* May happen during ddraw uninitialization */
7381 TRACE("Render target set, but swapchain does not exist!\n");
7382 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7386 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7387 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7388 This->render_targets[i] = NULL;
7391 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7392 This->stencilBufferTarget = NULL;
7398 case WINED3DRTYPE_TEXTURE:
7399 case WINED3DRTYPE_CUBETEXTURE:
7400 case WINED3DRTYPE_VOLUMETEXTURE:
7401 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7402 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7403 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7404 This->stateBlock->textures[counter] = NULL;
7406 if (This->updateStateBlock != This->stateBlock ){
7407 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7408 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7409 This->updateStateBlock->textures[counter] = NULL;
7414 case WINED3DRTYPE_VOLUME:
7415 /* TODO: nothing really? */
7417 case WINED3DRTYPE_VERTEXBUFFER:
7418 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7421 TRACE("Cleaning up stream pointers\n");
7423 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7424 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7425 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7427 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7428 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7429 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7430 This->updateStateBlock->streamSource[streamNumber] = 0;
7431 /* Set changed flag? */
7434 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) */
7435 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7436 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7437 This->stateBlock->streamSource[streamNumber] = 0;
7443 case WINED3DRTYPE_INDEXBUFFER:
7444 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7445 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7446 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7447 This->updateStateBlock->pIndexData = NULL;
7450 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7451 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7452 This->stateBlock->pIndexData = NULL;
7458 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7463 /* Remove the resource from the resourceStore */
7464 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7466 TRACE("Resource released\n");
7470 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7472 IWineD3DResourceImpl *resource, *cursor;
7474 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7476 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7477 TRACE("enumerating resource %p\n", resource);
7478 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7479 ret = pCallback((IWineD3DResource *) resource, pData);
7480 if(ret == S_FALSE) {
7481 TRACE("Canceling enumeration\n");
7488 /**********************************************************
7489 * IWineD3DDevice VTbl follows
7490 **********************************************************/
7492 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7494 /*** IUnknown methods ***/
7495 IWineD3DDeviceImpl_QueryInterface,
7496 IWineD3DDeviceImpl_AddRef,
7497 IWineD3DDeviceImpl_Release,
7498 /*** IWineD3DDevice methods ***/
7499 IWineD3DDeviceImpl_GetParent,
7500 /*** Creation methods**/
7501 IWineD3DDeviceImpl_CreateVertexBuffer,
7502 IWineD3DDeviceImpl_CreateIndexBuffer,
7503 IWineD3DDeviceImpl_CreateStateBlock,
7504 IWineD3DDeviceImpl_CreateSurface,
7505 IWineD3DDeviceImpl_CreateTexture,
7506 IWineD3DDeviceImpl_CreateVolumeTexture,
7507 IWineD3DDeviceImpl_CreateVolume,
7508 IWineD3DDeviceImpl_CreateCubeTexture,
7509 IWineD3DDeviceImpl_CreateQuery,
7510 IWineD3DDeviceImpl_CreateSwapChain,
7511 IWineD3DDeviceImpl_CreateVertexDeclaration,
7512 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7513 IWineD3DDeviceImpl_CreateVertexShader,
7514 IWineD3DDeviceImpl_CreatePixelShader,
7515 IWineD3DDeviceImpl_CreatePalette,
7516 /*** Odd functions **/
7517 IWineD3DDeviceImpl_Init3D,
7518 IWineD3DDeviceImpl_InitGDI,
7519 IWineD3DDeviceImpl_Uninit3D,
7520 IWineD3DDeviceImpl_UninitGDI,
7521 IWineD3DDeviceImpl_SetMultithreaded,
7522 IWineD3DDeviceImpl_EvictManagedResources,
7523 IWineD3DDeviceImpl_GetAvailableTextureMem,
7524 IWineD3DDeviceImpl_GetBackBuffer,
7525 IWineD3DDeviceImpl_GetCreationParameters,
7526 IWineD3DDeviceImpl_GetDeviceCaps,
7527 IWineD3DDeviceImpl_GetDirect3D,
7528 IWineD3DDeviceImpl_GetDisplayMode,
7529 IWineD3DDeviceImpl_SetDisplayMode,
7530 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7531 IWineD3DDeviceImpl_GetRasterStatus,
7532 IWineD3DDeviceImpl_GetSwapChain,
7533 IWineD3DDeviceImpl_Reset,
7534 IWineD3DDeviceImpl_SetDialogBoxMode,
7535 IWineD3DDeviceImpl_SetCursorProperties,
7536 IWineD3DDeviceImpl_SetCursorPosition,
7537 IWineD3DDeviceImpl_ShowCursor,
7538 IWineD3DDeviceImpl_TestCooperativeLevel,
7539 /*** Getters and setters **/
7540 IWineD3DDeviceImpl_SetClipPlane,
7541 IWineD3DDeviceImpl_GetClipPlane,
7542 IWineD3DDeviceImpl_SetClipStatus,
7543 IWineD3DDeviceImpl_GetClipStatus,
7544 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7545 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7546 IWineD3DDeviceImpl_SetDepthStencilSurface,
7547 IWineD3DDeviceImpl_GetDepthStencilSurface,
7548 IWineD3DDeviceImpl_SetFVF,
7549 IWineD3DDeviceImpl_GetFVF,
7550 IWineD3DDeviceImpl_SetGammaRamp,
7551 IWineD3DDeviceImpl_GetGammaRamp,
7552 IWineD3DDeviceImpl_SetIndices,
7553 IWineD3DDeviceImpl_GetIndices,
7554 IWineD3DDeviceImpl_SetBaseVertexIndex,
7555 IWineD3DDeviceImpl_GetBaseVertexIndex,
7556 IWineD3DDeviceImpl_SetLight,
7557 IWineD3DDeviceImpl_GetLight,
7558 IWineD3DDeviceImpl_SetLightEnable,
7559 IWineD3DDeviceImpl_GetLightEnable,
7560 IWineD3DDeviceImpl_SetMaterial,
7561 IWineD3DDeviceImpl_GetMaterial,
7562 IWineD3DDeviceImpl_SetNPatchMode,
7563 IWineD3DDeviceImpl_GetNPatchMode,
7564 IWineD3DDeviceImpl_SetPaletteEntries,
7565 IWineD3DDeviceImpl_GetPaletteEntries,
7566 IWineD3DDeviceImpl_SetPixelShader,
7567 IWineD3DDeviceImpl_GetPixelShader,
7568 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7569 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7570 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7571 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7572 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7573 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7574 IWineD3DDeviceImpl_SetRenderState,
7575 IWineD3DDeviceImpl_GetRenderState,
7576 IWineD3DDeviceImpl_SetRenderTarget,
7577 IWineD3DDeviceImpl_GetRenderTarget,
7578 IWineD3DDeviceImpl_SetFrontBackBuffers,
7579 IWineD3DDeviceImpl_SetSamplerState,
7580 IWineD3DDeviceImpl_GetSamplerState,
7581 IWineD3DDeviceImpl_SetScissorRect,
7582 IWineD3DDeviceImpl_GetScissorRect,
7583 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7584 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7585 IWineD3DDeviceImpl_SetStreamSource,
7586 IWineD3DDeviceImpl_GetStreamSource,
7587 IWineD3DDeviceImpl_SetStreamSourceFreq,
7588 IWineD3DDeviceImpl_GetStreamSourceFreq,
7589 IWineD3DDeviceImpl_SetTexture,
7590 IWineD3DDeviceImpl_GetTexture,
7591 IWineD3DDeviceImpl_SetTextureStageState,
7592 IWineD3DDeviceImpl_GetTextureStageState,
7593 IWineD3DDeviceImpl_SetTransform,
7594 IWineD3DDeviceImpl_GetTransform,
7595 IWineD3DDeviceImpl_SetVertexDeclaration,
7596 IWineD3DDeviceImpl_GetVertexDeclaration,
7597 IWineD3DDeviceImpl_SetVertexShader,
7598 IWineD3DDeviceImpl_GetVertexShader,
7599 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7600 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7601 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7602 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7603 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7604 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7605 IWineD3DDeviceImpl_SetViewport,
7606 IWineD3DDeviceImpl_GetViewport,
7607 IWineD3DDeviceImpl_MultiplyTransform,
7608 IWineD3DDeviceImpl_ValidateDevice,
7609 IWineD3DDeviceImpl_ProcessVertices,
7610 /*** State block ***/
7611 IWineD3DDeviceImpl_BeginStateBlock,
7612 IWineD3DDeviceImpl_EndStateBlock,
7613 /*** Scene management ***/
7614 IWineD3DDeviceImpl_BeginScene,
7615 IWineD3DDeviceImpl_EndScene,
7616 IWineD3DDeviceImpl_Present,
7617 IWineD3DDeviceImpl_Clear,
7619 IWineD3DDeviceImpl_DrawPrimitive,
7620 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7621 IWineD3DDeviceImpl_DrawPrimitiveUP,
7622 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7623 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7624 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7625 IWineD3DDeviceImpl_DrawRectPatch,
7626 IWineD3DDeviceImpl_DrawTriPatch,
7627 IWineD3DDeviceImpl_DeletePatch,
7628 IWineD3DDeviceImpl_ColorFill,
7629 IWineD3DDeviceImpl_UpdateTexture,
7630 IWineD3DDeviceImpl_UpdateSurface,
7631 IWineD3DDeviceImpl_GetFrontBufferData,
7632 /*** object tracking ***/
7633 IWineD3DDeviceImpl_ResourceReleased,
7634 IWineD3DDeviceImpl_EnumResources
7637 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7639 /*** IUnknown methods ***/
7640 IWineD3DDeviceImpl_QueryInterface,
7641 IWineD3DDeviceImpl_AddRef,
7642 IWineD3DDeviceImpl_Release,
7643 /*** IWineD3DDevice methods ***/
7644 IWineD3DDeviceImpl_GetParent,
7645 /*** Creation methods**/
7646 IWineD3DDeviceImpl_CreateVertexBuffer,
7647 IWineD3DDeviceImpl_CreateIndexBuffer,
7648 IWineD3DDeviceImpl_CreateStateBlock,
7649 IWineD3DDeviceImpl_CreateSurface,
7650 IWineD3DDeviceImpl_CreateTexture,
7651 IWineD3DDeviceImpl_CreateVolumeTexture,
7652 IWineD3DDeviceImpl_CreateVolume,
7653 IWineD3DDeviceImpl_CreateCubeTexture,
7654 IWineD3DDeviceImpl_CreateQuery,
7655 IWineD3DDeviceImpl_CreateSwapChain,
7656 IWineD3DDeviceImpl_CreateVertexDeclaration,
7657 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7658 IWineD3DDeviceImpl_CreateVertexShader,
7659 IWineD3DDeviceImpl_CreatePixelShader,
7660 IWineD3DDeviceImpl_CreatePalette,
7661 /*** Odd functions **/
7662 IWineD3DDeviceImpl_Init3D,
7663 IWineD3DDeviceImpl_InitGDI,
7664 IWineD3DDeviceImpl_Uninit3D,
7665 IWineD3DDeviceImpl_UninitGDI,
7666 IWineD3DDeviceImpl_SetMultithreaded,
7667 IWineD3DDeviceImpl_EvictManagedResources,
7668 IWineD3DDeviceImpl_GetAvailableTextureMem,
7669 IWineD3DDeviceImpl_GetBackBuffer,
7670 IWineD3DDeviceImpl_GetCreationParameters,
7671 IWineD3DDeviceImpl_GetDeviceCaps,
7672 IWineD3DDeviceImpl_GetDirect3D,
7673 IWineD3DDeviceImpl_GetDisplayMode,
7674 IWineD3DDeviceImpl_SetDisplayMode,
7675 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7676 IWineD3DDeviceImpl_GetRasterStatus,
7677 IWineD3DDeviceImpl_GetSwapChain,
7678 IWineD3DDeviceImpl_Reset,
7679 IWineD3DDeviceImpl_SetDialogBoxMode,
7680 IWineD3DDeviceImpl_SetCursorProperties,
7681 IWineD3DDeviceImpl_SetCursorPosition,
7682 IWineD3DDeviceImpl_ShowCursor,
7683 IWineD3DDeviceImpl_TestCooperativeLevel,
7684 /*** Getters and setters **/
7685 IWineD3DDeviceImpl_SetClipPlane,
7686 IWineD3DDeviceImpl_GetClipPlane,
7687 IWineD3DDeviceImpl_SetClipStatus,
7688 IWineD3DDeviceImpl_GetClipStatus,
7689 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7690 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7691 IWineD3DDeviceImpl_SetDepthStencilSurface,
7692 IWineD3DDeviceImpl_GetDepthStencilSurface,
7693 IWineD3DDeviceImpl_SetFVF,
7694 IWineD3DDeviceImpl_GetFVF,
7695 IWineD3DDeviceImpl_SetGammaRamp,
7696 IWineD3DDeviceImpl_GetGammaRamp,
7697 IWineD3DDeviceImpl_SetIndices,
7698 IWineD3DDeviceImpl_GetIndices,
7699 IWineD3DDeviceImpl_SetBaseVertexIndex,
7700 IWineD3DDeviceImpl_GetBaseVertexIndex,
7701 IWineD3DDeviceImpl_SetLight,
7702 IWineD3DDeviceImpl_GetLight,
7703 IWineD3DDeviceImpl_SetLightEnable,
7704 IWineD3DDeviceImpl_GetLightEnable,
7705 IWineD3DDeviceImpl_SetMaterial,
7706 IWineD3DDeviceImpl_GetMaterial,
7707 IWineD3DDeviceImpl_SetNPatchMode,
7708 IWineD3DDeviceImpl_GetNPatchMode,
7709 IWineD3DDeviceImpl_SetPaletteEntries,
7710 IWineD3DDeviceImpl_GetPaletteEntries,
7711 IWineD3DDeviceImpl_SetPixelShader,
7712 IWineD3DDeviceImpl_GetPixelShader,
7713 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7714 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7715 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7716 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7717 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7718 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7719 IWineD3DDeviceImpl_SetRenderState,
7720 IWineD3DDeviceImpl_GetRenderState,
7721 IWineD3DDeviceImpl_SetRenderTarget,
7722 IWineD3DDeviceImpl_GetRenderTarget,
7723 IWineD3DDeviceImpl_SetFrontBackBuffers,
7724 IWineD3DDeviceImpl_SetSamplerState,
7725 IWineD3DDeviceImpl_GetSamplerState,
7726 IWineD3DDeviceImpl_SetScissorRect,
7727 IWineD3DDeviceImpl_GetScissorRect,
7728 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7729 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7730 IWineD3DDeviceImpl_SetStreamSource,
7731 IWineD3DDeviceImpl_GetStreamSource,
7732 IWineD3DDeviceImpl_SetStreamSourceFreq,
7733 IWineD3DDeviceImpl_GetStreamSourceFreq,
7734 IWineD3DDeviceImpl_SetTexture,
7735 IWineD3DDeviceImpl_GetTexture,
7736 IWineD3DDeviceImpl_SetTextureStageState,
7737 IWineD3DDeviceImpl_GetTextureStageState,
7738 IWineD3DDeviceImpl_SetTransform,
7739 IWineD3DDeviceImpl_GetTransform,
7740 IWineD3DDeviceImpl_SetVertexDeclaration,
7741 IWineD3DDeviceImpl_GetVertexDeclaration,
7742 IWineD3DDeviceImpl_SetVertexShader,
7743 IWineD3DDeviceImpl_GetVertexShader,
7744 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7745 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7746 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7747 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7748 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7749 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7750 IWineD3DDeviceImpl_SetViewport,
7751 IWineD3DDeviceImpl_GetViewport,
7752 IWineD3DDeviceImpl_MultiplyTransform,
7753 IWineD3DDeviceImpl_ValidateDevice,
7754 IWineD3DDeviceImpl_ProcessVertices,
7755 /*** State block ***/
7756 IWineD3DDeviceImpl_BeginStateBlock,
7757 IWineD3DDeviceImpl_EndStateBlock,
7758 /*** Scene management ***/
7759 IWineD3DDeviceImpl_BeginScene,
7760 IWineD3DDeviceImpl_EndScene,
7761 IWineD3DDeviceImpl_Present,
7762 IWineD3DDeviceImpl_Clear,
7764 IWineD3DDeviceImpl_DrawPrimitive,
7765 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7766 IWineD3DDeviceImpl_DrawPrimitiveUP,
7767 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7768 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7769 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7770 IWineD3DDeviceImpl_DrawRectPatch,
7771 IWineD3DDeviceImpl_DrawTriPatch,
7772 IWineD3DDeviceImpl_DeletePatch,
7773 IWineD3DDeviceImpl_ColorFill,
7774 IWineD3DDeviceImpl_UpdateTexture,
7775 IWineD3DDeviceImpl_UpdateSurface,
7776 IWineD3DDeviceImpl_GetFrontBufferData,
7777 /*** object tracking ***/
7778 IWineD3DDeviceImpl_ResourceReleased,
7779 IWineD3DDeviceImpl_EnumResources
7782 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7783 WINED3DRS_ALPHABLENDENABLE ,
7784 WINED3DRS_ALPHAFUNC ,
7785 WINED3DRS_ALPHAREF ,
7786 WINED3DRS_ALPHATESTENABLE ,
7788 WINED3DRS_COLORWRITEENABLE ,
7789 WINED3DRS_DESTBLEND ,
7790 WINED3DRS_DITHERENABLE ,
7791 WINED3DRS_FILLMODE ,
7792 WINED3DRS_FOGDENSITY ,
7794 WINED3DRS_FOGSTART ,
7795 WINED3DRS_LASTPIXEL ,
7796 WINED3DRS_SHADEMODE ,
7797 WINED3DRS_SRCBLEND ,
7798 WINED3DRS_STENCILENABLE ,
7799 WINED3DRS_STENCILFAIL ,
7800 WINED3DRS_STENCILFUNC ,
7801 WINED3DRS_STENCILMASK ,
7802 WINED3DRS_STENCILPASS ,
7803 WINED3DRS_STENCILREF ,
7804 WINED3DRS_STENCILWRITEMASK ,
7805 WINED3DRS_STENCILZFAIL ,
7806 WINED3DRS_TEXTUREFACTOR ,
7817 WINED3DRS_ZWRITEENABLE
7820 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7821 WINED3DTSS_ADDRESSW ,
7822 WINED3DTSS_ALPHAARG0 ,
7823 WINED3DTSS_ALPHAARG1 ,
7824 WINED3DTSS_ALPHAARG2 ,
7825 WINED3DTSS_ALPHAOP ,
7826 WINED3DTSS_BUMPENVLOFFSET ,
7827 WINED3DTSS_BUMPENVLSCALE ,
7828 WINED3DTSS_BUMPENVMAT00 ,
7829 WINED3DTSS_BUMPENVMAT01 ,
7830 WINED3DTSS_BUMPENVMAT10 ,
7831 WINED3DTSS_BUMPENVMAT11 ,
7832 WINED3DTSS_COLORARG0 ,
7833 WINED3DTSS_COLORARG1 ,
7834 WINED3DTSS_COLORARG2 ,
7835 WINED3DTSS_COLOROP ,
7836 WINED3DTSS_RESULTARG ,
7837 WINED3DTSS_TEXCOORDINDEX ,
7838 WINED3DTSS_TEXTURETRANSFORMFLAGS
7841 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7842 WINED3DSAMP_ADDRESSU ,
7843 WINED3DSAMP_ADDRESSV ,
7844 WINED3DSAMP_ADDRESSW ,
7845 WINED3DSAMP_BORDERCOLOR ,
7846 WINED3DSAMP_MAGFILTER ,
7847 WINED3DSAMP_MINFILTER ,
7848 WINED3DSAMP_MIPFILTER ,
7849 WINED3DSAMP_MIPMAPLODBIAS ,
7850 WINED3DSAMP_MAXMIPLEVEL ,
7851 WINED3DSAMP_MAXANISOTROPY ,
7852 WINED3DSAMP_SRGBTEXTURE ,
7853 WINED3DSAMP_ELEMENTINDEX
7856 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7858 WINED3DRS_AMBIENTMATERIALSOURCE ,
7859 WINED3DRS_CLIPPING ,
7860 WINED3DRS_CLIPPLANEENABLE ,
7861 WINED3DRS_COLORVERTEX ,
7862 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7863 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7864 WINED3DRS_FOGDENSITY ,
7866 WINED3DRS_FOGSTART ,
7867 WINED3DRS_FOGTABLEMODE ,
7868 WINED3DRS_FOGVERTEXMODE ,
7869 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7870 WINED3DRS_LIGHTING ,
7871 WINED3DRS_LOCALVIEWER ,
7872 WINED3DRS_MULTISAMPLEANTIALIAS ,
7873 WINED3DRS_MULTISAMPLEMASK ,
7874 WINED3DRS_NORMALIZENORMALS ,
7875 WINED3DRS_PATCHEDGESTYLE ,
7876 WINED3DRS_POINTSCALE_A ,
7877 WINED3DRS_POINTSCALE_B ,
7878 WINED3DRS_POINTSCALE_C ,
7879 WINED3DRS_POINTSCALEENABLE ,
7880 WINED3DRS_POINTSIZE ,
7881 WINED3DRS_POINTSIZE_MAX ,
7882 WINED3DRS_POINTSIZE_MIN ,
7883 WINED3DRS_POINTSPRITEENABLE ,
7884 WINED3DRS_RANGEFOGENABLE ,
7885 WINED3DRS_SPECULARMATERIALSOURCE ,
7886 WINED3DRS_TWEENFACTOR ,
7887 WINED3DRS_VERTEXBLEND ,
7888 WINED3DRS_CULLMODE ,
7892 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7893 WINED3DTSS_TEXCOORDINDEX ,
7894 WINED3DTSS_TEXTURETRANSFORMFLAGS
7897 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7898 WINED3DSAMP_DMAPOFFSET
7901 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7902 DWORD rep = This->StateTable[state].representative;
7906 WineD3DContext *context;
7909 for(i = 0; i < This->numContexts; i++) {
7910 context = This->contexts[i];
7911 if(isStateDirty(context, rep)) continue;
7913 context->dirtyArray[context->numDirtyEntries++] = rep;
7916 context->isStateDirty[idx] |= (1 << shift);
7920 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7921 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7922 /* The drawable size of a pbuffer render target is the current pbuffer size
7924 *width = dev->pbufferWidth;
7925 *height = dev->pbufferHeight;
7928 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7929 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7931 *width = This->pow2Width;
7932 *height = This->pow2Height;
7935 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7936 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7937 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7938 * current context's drawable, which is the size of the back buffer of the swapchain
7939 * the active context belongs to. The back buffer of the swapchain is stored as the
7940 * surface the context belongs to.
7942 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7943 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;