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;
1878 if (!pFunction) return WINED3DERR_INVALIDCALL;
1880 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1881 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1883 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1885 if (vertex_declaration) {
1886 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1889 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1891 if (WINED3D_OK != hr) {
1892 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1893 IWineD3DVertexShader_Release(*ppVertexShader);
1894 return WINED3DERR_INVALIDCALL;
1896 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1901 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1902 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1903 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1904 HRESULT hr = WINED3D_OK;
1906 if (!pFunction) return WINED3DERR_INVALIDCALL;
1908 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1909 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1910 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1911 if (WINED3D_OK == hr) {
1912 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1913 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1915 WARN("(%p) : Failed to create pixel shader\n", This);
1921 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags,
1922 const PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent)
1924 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1925 IWineD3DPaletteImpl *object;
1927 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1929 /* Create the new object */
1930 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1932 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1933 return E_OUTOFMEMORY;
1936 object->lpVtbl = &IWineD3DPalette_Vtbl;
1938 object->Flags = Flags;
1939 object->parent = Parent;
1940 object->wineD3DDevice = This;
1941 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1943 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1946 HeapFree( GetProcessHeap(), 0, object);
1947 return E_OUTOFMEMORY;
1950 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1952 IWineD3DPalette_Release((IWineD3DPalette *) object);
1956 *Palette = (IWineD3DPalette *) object;
1961 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1965 HDC dcb = NULL, dcs = NULL;
1966 WINEDDCOLORKEY colorkey;
1968 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1971 GetObjectA(hbm, sizeof(BITMAP), &bm);
1972 dcb = CreateCompatibleDC(NULL);
1974 SelectObject(dcb, hbm);
1978 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1979 * couldn't be loaded
1981 memset(&bm, 0, sizeof(bm));
1986 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1987 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1988 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1990 ERR("Wine logo requested, but failed to create surface\n");
1995 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1996 if(FAILED(hr)) goto out;
1997 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1998 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
2000 colorkey.dwColorSpaceLowValue = 0;
2001 colorkey.dwColorSpaceHighValue = 0;
2002 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2004 /* Fill the surface with a white color to show that wined3d is there */
2005 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2018 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2020 /* Under DirectX you can have texture stage operations even if no texture is
2021 bound, whereas opengl will only do texture operations when a valid texture is
2022 bound. We emulate this by creating dummy textures and binding them to each
2023 texture stage, but disable all stages by default. Hence if a stage is enabled
2024 then the default texture will kick in until replaced by a SetTexture call */
2027 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2028 /* The dummy texture does not have client storage backing */
2029 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2030 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2032 for (i = 0; i < GL_LIMITS(textures); i++) {
2033 GLubyte white = 255;
2035 /* Make appropriate texture active */
2036 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2037 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2038 checkGLcall("glActiveTextureARB");
2040 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2043 /* Generate an opengl texture name */
2044 glGenTextures(1, &This->dummyTextureName[i]);
2045 checkGLcall("glGenTextures");
2046 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2048 /* Generate a dummy 2d texture (not using 1d because they cause many
2049 * DRI drivers fall back to sw) */
2050 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2051 checkGLcall("glBindTexture");
2053 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2054 checkGLcall("glTexImage2D");
2056 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2057 /* Reenable because if supported it is enabled by default */
2058 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2059 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2065 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2067 IWineD3DSwapChainImpl *swapchain = NULL;
2072 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateSwapChain);
2073 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2074 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2076 /* TODO: Test if OpenGL is compiled in and loaded */
2078 TRACE("(%p) : Creating stateblock\n", This);
2079 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2080 hr = IWineD3DDevice_CreateStateBlock(iface,
2082 (IWineD3DStateBlock **)&This->stateBlock,
2084 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2085 WARN("Failed to create stateblock\n");
2088 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2089 This->updateStateBlock = This->stateBlock;
2090 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2092 hr = allocate_shader_constants(This->updateStateBlock);
2093 if (WINED3D_OK != hr) {
2097 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2098 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2100 This->NumberOfPalettes = 1;
2101 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2102 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2103 ERR("Out of memory!\n");
2106 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2107 if(!This->palettes[0]) {
2108 ERR("Out of memory!\n");
2111 for (i = 0; i < 256; ++i) {
2112 This->palettes[0][i].peRed = 0xFF;
2113 This->palettes[0][i].peGreen = 0xFF;
2114 This->palettes[0][i].peBlue = 0xFF;
2115 This->palettes[0][i].peFlags = 0xFF;
2117 This->currentPalette = 0;
2119 /* Initialize the texture unit mapping to a 1:1 mapping */
2120 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2121 if (state < GL_LIMITS(fragment_samplers)) {
2122 This->texUnitMap[state] = state;
2123 This->rev_tex_unit_map[state] = state;
2125 This->texUnitMap[state] = -1;
2126 This->rev_tex_unit_map[state] = -1;
2130 /* Setup the implicit swapchain */
2131 TRACE("Creating implicit swapchain\n");
2132 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2133 if (FAILED(hr) || !swapchain) {
2134 WARN("Failed to create implicit swapchain\n");
2138 This->NumberOfSwapChains = 1;
2139 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2140 if(!This->swapchains) {
2141 ERR("Out of memory!\n");
2144 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2146 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2147 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2148 This->render_targets[0] = swapchain->backBuffer[0];
2149 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2152 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2153 This->render_targets[0] = swapchain->frontBuffer;
2154 This->lastActiveRenderTarget = swapchain->frontBuffer;
2156 IWineD3DSurface_AddRef(This->render_targets[0]);
2157 This->activeContext = swapchain->context[0];
2158 This->lastThread = GetCurrentThreadId();
2160 /* Depth Stencil support */
2161 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2162 if (NULL != This->stencilBufferTarget) {
2163 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2166 hr = This->shader_backend->shader_alloc_private(iface);
2168 TRACE("Shader private data couldn't be allocated\n");
2171 hr = This->frag_pipe->alloc_private(iface);
2173 TRACE("Fragment pipeline private data couldn't be allocated\n");
2176 hr = This->blitter->alloc_private(iface);
2178 TRACE("Blitter private data couldn't be allocated\n");
2182 /* Set up some starting GL setup */
2184 /* Setup all the devices defaults */
2185 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2186 create_dummy_textures(This);
2190 { /* Set a default viewport */
2194 vp.Width = pPresentationParameters->BackBufferWidth;
2195 vp.Height = pPresentationParameters->BackBufferHeight;
2198 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2201 /* Initialize the current view state */
2202 This->view_ident = 1;
2203 This->contexts[0]->last_was_rhw = 0;
2204 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2205 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2207 switch(wined3d_settings.offscreen_rendering_mode) {
2210 This->offscreenBuffer = GL_BACK;
2213 case ORM_BACKBUFFER:
2215 if(This->activeContext->aux_buffers > 0) {
2216 TRACE("Using auxilliary buffer for offscreen rendering\n");
2217 This->offscreenBuffer = GL_AUX0;
2219 TRACE("Using back buffer for offscreen rendering\n");
2220 This->offscreenBuffer = GL_BACK;
2225 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2228 /* Clear the screen */
2229 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2230 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2233 This->d3d_initialized = TRUE;
2235 if(wined3d_settings.logo) {
2236 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2238 This->highest_dirty_ps_const = 0;
2239 This->highest_dirty_vs_const = 0;
2243 HeapFree(GetProcessHeap(), 0, This->render_targets);
2244 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2245 HeapFree(GetProcessHeap(), 0, This->swapchains);
2246 This->NumberOfSwapChains = 0;
2247 if(This->palettes) {
2248 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2249 HeapFree(GetProcessHeap(), 0, This->palettes);
2251 This->NumberOfPalettes = 0;
2253 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2255 if(This->stateBlock) {
2256 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2257 This->stateBlock = NULL;
2259 if (This->blit_priv) {
2260 This->blitter->free_private(iface);
2262 if (This->fragment_priv) {
2263 This->frag_pipe->free_private(iface);
2265 if (This->shader_priv) {
2266 This->shader_backend->shader_free_private(iface);
2271 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATESWAPCHAIN D3DCB_CreateSwapChain) {
2272 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2273 IWineD3DSwapChainImpl *swapchain = NULL;
2276 /* Setup the implicit swapchain */
2277 TRACE("Creating implicit swapchain\n");
2278 hr=D3DCB_CreateSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2279 if (FAILED(hr) || !swapchain) {
2280 WARN("Failed to create implicit swapchain\n");
2284 This->NumberOfSwapChains = 1;
2285 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2286 if(!This->swapchains) {
2287 ERR("Out of memory!\n");
2290 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2294 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2298 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2302 TRACE("(%p)\n", This);
2304 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2306 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2307 * it was created. Thus make sure a context is active for the glDelete* calls
2309 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2311 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2313 TRACE("Deleting high order patches\n");
2314 for(i = 0; i < PATCHMAP_SIZE; i++) {
2315 struct list *e1, *e2;
2316 struct WineD3DRectPatch *patch;
2317 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2318 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2319 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2323 /* Delete the palette conversion shader if it is around */
2324 if(This->paletteConversionShader) {
2326 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2328 This->paletteConversionShader = 0;
2331 /* Delete the pbuffer context if there is any */
2332 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2334 /* Delete the mouse cursor texture */
2335 if(This->cursorTexture) {
2337 glDeleteTextures(1, &This->cursorTexture);
2339 This->cursorTexture = 0;
2342 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2343 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2345 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2346 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2349 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2350 * private data, it might contain opengl pointers
2352 if(This->depth_blt_texture) {
2353 glDeleteTextures(1, &This->depth_blt_texture);
2354 This->depth_blt_texture = 0;
2356 if (This->depth_blt_rb) {
2357 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2358 This->depth_blt_rb = 0;
2359 This->depth_blt_rb_w = 0;
2360 This->depth_blt_rb_h = 0;
2363 /* Release the update stateblock */
2364 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2365 if(This->updateStateBlock != This->stateBlock)
2366 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2368 This->updateStateBlock = NULL;
2370 { /* because were not doing proper internal refcounts releasing the primary state block
2371 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2372 to set this->stateBlock = NULL; first */
2373 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2374 This->stateBlock = NULL;
2376 /* Release the stateblock */
2377 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2378 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2382 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2383 This->blitter->free_private(iface);
2384 This->frag_pipe->free_private(iface);
2385 This->shader_backend->shader_free_private(iface);
2387 /* Release the buffers (with sanity checks)*/
2388 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2389 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2390 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2391 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2393 This->stencilBufferTarget = NULL;
2395 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2396 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2397 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2399 TRACE("Setting rendertarget to NULL\n");
2400 This->render_targets[0] = NULL;
2402 if (This->auto_depth_stencil_buffer) {
2403 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2404 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2406 This->auto_depth_stencil_buffer = NULL;
2409 for(i=0; i < This->NumberOfSwapChains; i++) {
2410 TRACE("Releasing the implicit swapchain %d\n", i);
2411 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2412 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2416 HeapFree(GetProcessHeap(), 0, This->swapchains);
2417 This->swapchains = NULL;
2418 This->NumberOfSwapChains = 0;
2420 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2421 HeapFree(GetProcessHeap(), 0, This->palettes);
2422 This->palettes = NULL;
2423 This->NumberOfPalettes = 0;
2425 HeapFree(GetProcessHeap(), 0, This->render_targets);
2426 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2427 This->render_targets = NULL;
2428 This->draw_buffers = NULL;
2430 This->d3d_initialized = FALSE;
2434 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2438 for(i=0; i < This->NumberOfSwapChains; i++) {
2439 TRACE("Releasing the implicit swapchain %d\n", i);
2440 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2441 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2445 HeapFree(GetProcessHeap(), 0, This->swapchains);
2446 This->swapchains = NULL;
2447 This->NumberOfSwapChains = 0;
2451 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2452 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2453 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2455 * There is no way to deactivate thread safety once it is enabled.
2457 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2460 /*For now just store the flag(needed in case of ddraw) */
2461 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2466 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain,
2467 const WINED3DDISPLAYMODE* pMode) {
2469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2471 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2474 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2476 /* Resize the screen even without a window:
2477 * The app could have unset it with SetCooperativeLevel, but not called
2478 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2479 * but we don't have any hwnd
2482 memset(&devmode, 0, sizeof(devmode));
2483 devmode.dmSize = sizeof(devmode);
2484 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2485 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2486 devmode.dmPelsWidth = pMode->Width;
2487 devmode.dmPelsHeight = pMode->Height;
2489 devmode.dmDisplayFrequency = pMode->RefreshRate;
2490 if (pMode->RefreshRate != 0) {
2491 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2494 /* Only change the mode if necessary */
2495 if( (This->ddraw_width == pMode->Width) &&
2496 (This->ddraw_height == pMode->Height) &&
2497 (This->ddraw_format == pMode->Format) &&
2498 (pMode->RefreshRate == 0) ) {
2502 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2503 if (ret != DISP_CHANGE_SUCCESSFUL) {
2504 if(devmode.dmDisplayFrequency != 0) {
2505 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2506 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2507 devmode.dmDisplayFrequency = 0;
2508 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2510 if(ret != DISP_CHANGE_SUCCESSFUL) {
2511 return WINED3DERR_NOTAVAILABLE;
2515 /* Store the new values */
2516 This->ddraw_width = pMode->Width;
2517 This->ddraw_height = pMode->Height;
2518 This->ddraw_format = pMode->Format;
2520 /* And finally clip mouse to our screen */
2521 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2522 ClipCursor(&clip_rc);
2527 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 *ppD3D= This->wineD3D;
2530 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2531 IWineD3D_AddRef(*ppD3D);
2535 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2536 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2538 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2539 (This->adapter->TextureRam/(1024*1024)),
2540 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2541 /* return simulated texture memory left */
2542 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2550 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2553 /* Update the current state block */
2554 This->updateStateBlock->changed.fvf = TRUE;
2556 if(This->updateStateBlock->fvf == fvf) {
2557 TRACE("Application is setting the old fvf over, nothing to do\n");
2561 This->updateStateBlock->fvf = fvf;
2562 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2563 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2568 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2569 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2570 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2571 *pfvf = This->stateBlock->fvf;
2576 * Get / Set Stream Source
2578 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2579 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2580 IWineD3DVertexBuffer *oldSrc;
2582 if (StreamNumber >= MAX_STREAMS) {
2583 WARN("Stream out of range %d\n", StreamNumber);
2584 return WINED3DERR_INVALIDCALL;
2585 } else if(OffsetInBytes & 0x3) {
2586 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2587 return WINED3DERR_INVALIDCALL;
2590 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2591 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2593 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2595 if(oldSrc == pStreamData &&
2596 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2597 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2598 TRACE("Application is setting the old values over, nothing to do\n");
2602 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2604 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2605 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2608 /* Handle recording of state blocks */
2609 if (This->isRecordingState) {
2610 TRACE("Recording... not performing anything\n");
2611 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2612 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2616 /* Need to do a getParent and pass the references up */
2617 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2618 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2619 so for now, just count internally */
2620 if (pStreamData != NULL) {
2621 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2622 InterlockedIncrement(&vbImpl->bindCount);
2623 IWineD3DVertexBuffer_AddRef(pStreamData);
2625 if (oldSrc != NULL) {
2626 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2627 IWineD3DVertexBuffer_Release(oldSrc);
2630 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2635 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2636 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2638 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2639 This->stateBlock->streamSource[StreamNumber],
2640 This->stateBlock->streamOffset[StreamNumber],
2641 This->stateBlock->streamStride[StreamNumber]);
2643 if (StreamNumber >= MAX_STREAMS) {
2644 WARN("Stream out of range %d\n", StreamNumber);
2645 return WINED3DERR_INVALIDCALL;
2647 *pStream = This->stateBlock->streamSource[StreamNumber];
2648 *pStride = This->stateBlock->streamStride[StreamNumber];
2650 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2653 if (*pStream != NULL) {
2654 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2659 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2660 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2661 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2662 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2664 /* Verify input at least in d3d9 this is invalid*/
2665 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2666 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2667 return WINED3DERR_INVALIDCALL;
2669 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2670 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2671 return WINED3DERR_INVALIDCALL;
2674 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2675 return WINED3DERR_INVALIDCALL;
2678 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2679 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2681 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2682 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2684 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2685 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2692 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2695 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2696 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2698 TRACE("(%p) : returning %d\n", This, *Divider);
2704 * Get / Set & Multiply Transform
2706 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2709 /* Most of this routine, comments included copied from ddraw tree initially: */
2710 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2712 /* Handle recording of state blocks */
2713 if (This->isRecordingState) {
2714 TRACE("Recording... not performing anything\n");
2715 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2716 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2721 * If the new matrix is the same as the current one,
2722 * we cut off any further processing. this seems to be a reasonable
2723 * optimization because as was noticed, some apps (warcraft3 for example)
2724 * tend towards setting the same matrix repeatedly for some reason.
2726 * From here on we assume that the new matrix is different, wherever it matters.
2728 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2729 TRACE("The app is setting the same matrix over again\n");
2732 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2736 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2737 where ViewMat = Camera space, WorldMat = world space.
2739 In OpenGL, camera and world space is combined into GL_MODELVIEW
2740 matrix. The Projection matrix stay projection matrix.
2743 /* Capture the times we can just ignore the change for now */
2744 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2745 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2746 /* Handled by the state manager */
2749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2753 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2754 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2755 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2756 *pMatrix = This->stateBlock->transforms[State];
2760 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2761 const WINED3DMATRIX *mat = NULL;
2764 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2765 * below means it will be recorded in a state block change, but it
2766 * works regardless where it is recorded.
2767 * If this is found to be wrong, change to StateBlock.
2769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2770 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2772 if (State < HIGHEST_TRANSFORMSTATE)
2774 mat = &This->updateStateBlock->transforms[State];
2776 FIXME("Unhandled transform state!!\n");
2779 multiply_matrix(&temp, mat, pMatrix);
2781 /* Apply change via set transform - will reapply to eg. lights this way */
2782 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2788 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2789 you can reference any indexes you want as long as that number max are enabled at any
2790 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2791 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2792 but when recording, just build a chain pretty much of commands to be replayed. */
2794 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2796 PLIGHTINFOEL *object = NULL;
2797 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2800 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2801 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2803 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2807 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2808 return WINED3DERR_INVALIDCALL;
2811 switch(pLight->Type) {
2812 case WINED3DLIGHT_POINT:
2813 case WINED3DLIGHT_SPOT:
2814 case WINED3DLIGHT_PARALLELPOINT:
2815 case WINED3DLIGHT_GLSPOT:
2816 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2819 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2820 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2821 return WINED3DERR_INVALIDCALL;
2825 case WINED3DLIGHT_DIRECTIONAL:
2826 /* Ignores attenuation */
2830 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2831 return WINED3DERR_INVALIDCALL;
2834 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2835 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2836 if(object->OriginalIndex == Index) break;
2841 TRACE("Adding new light\n");
2842 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2844 ERR("Out of memory error when allocating a light\n");
2845 return E_OUTOFMEMORY;
2847 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2848 object->glIndex = -1;
2849 object->OriginalIndex = Index;
2850 object->changed = TRUE;
2853 /* Initialize the object */
2854 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,
2855 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2856 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2857 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2858 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2859 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2860 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2862 /* Save away the information */
2863 object->OriginalParms = *pLight;
2865 switch (pLight->Type) {
2866 case WINED3DLIGHT_POINT:
2868 object->lightPosn[0] = pLight->Position.x;
2869 object->lightPosn[1] = pLight->Position.y;
2870 object->lightPosn[2] = pLight->Position.z;
2871 object->lightPosn[3] = 1.0f;
2872 object->cutoff = 180.0f;
2876 case WINED3DLIGHT_DIRECTIONAL:
2878 object->lightPosn[0] = -pLight->Direction.x;
2879 object->lightPosn[1] = -pLight->Direction.y;
2880 object->lightPosn[2] = -pLight->Direction.z;
2881 object->lightPosn[3] = 0.0;
2882 object->exponent = 0.0f;
2883 object->cutoff = 180.0f;
2886 case WINED3DLIGHT_SPOT:
2888 object->lightPosn[0] = pLight->Position.x;
2889 object->lightPosn[1] = pLight->Position.y;
2890 object->lightPosn[2] = pLight->Position.z;
2891 object->lightPosn[3] = 1.0;
2894 object->lightDirn[0] = pLight->Direction.x;
2895 object->lightDirn[1] = pLight->Direction.y;
2896 object->lightDirn[2] = pLight->Direction.z;
2897 object->lightDirn[3] = 1.0;
2900 * opengl-ish and d3d-ish spot lights use too different models for the
2901 * light "intensity" as a function of the angle towards the main light direction,
2902 * so we only can approximate very roughly.
2903 * however spot lights are rather rarely used in games (if ever used at all).
2904 * furthermore if still used, probably nobody pays attention to such details.
2906 if (pLight->Falloff == 0) {
2907 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2908 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2909 * will always be 1.0 for both of them, and we don't have to care for the
2910 * rest of the rather complex calculation
2912 object->exponent = 0;
2914 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2915 if (rho < 0.0001) rho = 0.0001f;
2916 object->exponent = -0.3/log(cos(rho/2));
2918 if (object->exponent > 128.0) {
2919 object->exponent = 128.0;
2921 object->cutoff = pLight->Phi*90/M_PI;
2927 FIXME("Unrecognized light type %d\n", pLight->Type);
2930 /* Update the live definitions if the light is currently assigned a glIndex */
2931 if (object->glIndex != -1 && !This->isRecordingState) {
2932 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2937 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2938 PLIGHTINFOEL *lightInfo = NULL;
2939 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2940 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2942 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2944 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2945 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2946 if(lightInfo->OriginalIndex == Index) break;
2950 if (lightInfo == NULL) {
2951 TRACE("Light information requested but light not defined\n");
2952 return WINED3DERR_INVALIDCALL;
2955 *pLight = lightInfo->OriginalParms;
2960 * Get / Set Light Enable
2961 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2963 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2964 PLIGHTINFOEL *lightInfo = NULL;
2965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2966 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2968 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2970 /* Tests show true = 128...not clear why */
2971 Enable = Enable? 128: 0;
2973 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2974 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2975 if(lightInfo->OriginalIndex == Index) break;
2978 TRACE("Found light: %p\n", lightInfo);
2980 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2981 if (lightInfo == NULL) {
2983 TRACE("Light enabled requested but light not defined, so defining one!\n");
2984 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2986 /* Search for it again! Should be fairly quick as near head of list */
2987 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2988 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2989 if(lightInfo->OriginalIndex == Index) break;
2992 if (lightInfo == NULL) {
2993 FIXME("Adding default lights has failed dismally\n");
2994 return WINED3DERR_INVALIDCALL;
2998 lightInfo->enabledChanged = TRUE;
3000 if(lightInfo->glIndex != -1) {
3001 if(!This->isRecordingState) {
3002 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3005 This->updateStateBlock->activeLights[lightInfo->glIndex] = NULL;
3006 lightInfo->glIndex = -1;
3008 TRACE("Light already disabled, nothing to do\n");
3010 lightInfo->enabled = FALSE;
3012 lightInfo->enabled = TRUE;
3013 if (lightInfo->glIndex != -1) {
3015 TRACE("Nothing to do as light was enabled\n");
3018 /* Find a free gl light */
3019 for(i = 0; i < This->maxConcurrentLights; i++) {
3020 if(This->updateStateBlock->activeLights[i] == NULL) {
3021 This->updateStateBlock->activeLights[i] = lightInfo;
3022 lightInfo->glIndex = i;
3026 if(lightInfo->glIndex == -1) {
3027 /* Our tests show that Windows returns D3D_OK in this situation, even with
3028 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3029 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3030 * as well for those lights.
3032 * TODO: Test how this affects rendering
3034 FIXME("Too many concurrently active lights\n");
3038 /* i == lightInfo->glIndex */
3039 if(!This->isRecordingState) {
3040 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3048 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3050 PLIGHTINFOEL *lightInfo = NULL;
3051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3053 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3054 TRACE("(%p) : for idx(%d)\n", This, Index);
3056 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3057 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3058 if(lightInfo->OriginalIndex == Index) break;
3062 if (lightInfo == NULL) {
3063 TRACE("Light enabled state requested but light not defined\n");
3064 return WINED3DERR_INVALIDCALL;
3066 /* true is 128 according to SetLightEnable */
3067 *pEnable = lightInfo->enabled ? 128 : 0;
3072 * Get / Set Clip Planes
3074 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3076 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3078 /* Validate Index */
3079 if (Index >= GL_LIMITS(clipplanes)) {
3080 TRACE("Application has requested clipplane this device doesn't support\n");
3081 return WINED3DERR_INVALIDCALL;
3084 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3086 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3087 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3088 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3089 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3090 TRACE("Application is setting old values over, nothing to do\n");
3094 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3095 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3096 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3097 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3099 /* Handle recording of state blocks */
3100 if (This->isRecordingState) {
3101 TRACE("Recording... not performing anything\n");
3105 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3110 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3111 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3112 TRACE("(%p) : for idx %d\n", This, Index);
3114 /* Validate Index */
3115 if (Index >= GL_LIMITS(clipplanes)) {
3116 TRACE("Application has requested clipplane this device doesn't support\n");
3117 return WINED3DERR_INVALIDCALL;
3120 pPlane[0] = This->stateBlock->clipplane[Index][0];
3121 pPlane[1] = This->stateBlock->clipplane[Index][1];
3122 pPlane[2] = This->stateBlock->clipplane[Index][2];
3123 pPlane[3] = This->stateBlock->clipplane[Index][3];
3128 * Get / Set Clip Plane Status
3129 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3131 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3133 FIXME("(%p) : stub\n", This);
3134 if (NULL == pClipStatus) {
3135 return WINED3DERR_INVALIDCALL;
3137 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3138 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3142 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 FIXME("(%p) : stub\n", This);
3145 if (NULL == pClipStatus) {
3146 return WINED3DERR_INVALIDCALL;
3148 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3149 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3154 * Get / Set Material
3156 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3157 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3159 This->updateStateBlock->changed.material = TRUE;
3160 This->updateStateBlock->material = *pMaterial;
3162 /* Handle recording of state blocks */
3163 if (This->isRecordingState) {
3164 TRACE("Recording... not performing anything\n");
3168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3172 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 *pMaterial = This->updateStateBlock->material;
3175 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3176 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3177 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3178 pMaterial->Ambient.b, pMaterial->Ambient.a);
3179 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3180 pMaterial->Specular.b, pMaterial->Specular.a);
3181 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3182 pMaterial->Emissive.b, pMaterial->Emissive.a);
3183 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 IWineD3DIndexBuffer *oldIdxs;
3195 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3196 oldIdxs = This->updateStateBlock->pIndexData;
3198 This->updateStateBlock->changed.indices = TRUE;
3199 This->updateStateBlock->pIndexData = pIndexData;
3201 /* Handle recording of state blocks */
3202 if (This->isRecordingState) {
3203 TRACE("Recording... not performing anything\n");
3204 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3205 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3209 if(oldIdxs != pIndexData) {
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3211 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3212 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 *ppIndexData = This->stateBlock->pIndexData;
3222 /* up ref count on ppindexdata */
3224 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3225 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3227 TRACE("(%p) No index data set\n", This);
3229 TRACE("Returning %p\n", *ppIndexData);
3234 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3235 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 TRACE("(%p)->(%d)\n", This, BaseIndex);
3239 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3240 TRACE("Application is setting the old value over, nothing to do\n");
3244 This->updateStateBlock->baseVertexIndex = BaseIndex;
3246 if (This->isRecordingState) {
3247 TRACE("Recording... not performing anything\n");
3250 /* The base vertex index affects the stream sources */
3251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3255 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 TRACE("(%p) : base_index %p\n", This, base_index);
3259 *base_index = This->stateBlock->baseVertexIndex;
3261 TRACE("Returning %u\n", *base_index);
3267 * Get / Set Viewports
3269 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 TRACE("(%p)\n", This);
3273 This->updateStateBlock->changed.viewport = TRUE;
3274 This->updateStateBlock->viewport = *pViewport;
3276 /* Handle recording of state blocks */
3277 if (This->isRecordingState) {
3278 TRACE("Recording... not performing anything\n");
3282 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3283 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 TRACE("(%p)\n", This);
3293 *pViewport = This->stateBlock->viewport;
3298 * Get / Set Render States
3299 * TODO: Verify against dx9 definitions
3301 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 DWORD oldValue = This->stateBlock->renderState[State];
3306 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3308 This->updateStateBlock->changed.renderState[State] = TRUE;
3309 This->updateStateBlock->renderState[State] = Value;
3311 /* Handle recording of state blocks */
3312 if (This->isRecordingState) {
3313 TRACE("Recording... not performing anything\n");
3317 /* Compared here and not before the assignment to allow proper stateblock recording */
3318 if(Value == oldValue) {
3319 TRACE("Application is setting the old value over, nothing to do\n");
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3327 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3330 *pValue = This->stateBlock->renderState[State];
3335 * Get / Set Sampler States
3336 * TODO: Verify against dx9 definitions
3339 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3343 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3344 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3346 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3347 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3350 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3351 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3352 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3355 * SetSampler is designed to allow for more than the standard up to 8 textures
3356 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3357 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3359 * http://developer.nvidia.com/object/General_FAQ.html#t6
3361 * There are two new settings for GForce
3363 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3364 * and the texture one:
3365 * GL_MAX_TEXTURE_COORDS_ARB.
3366 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3369 oldValue = This->stateBlock->samplerState[Sampler][Type];
3370 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3371 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3373 /* Handle recording of state blocks */
3374 if (This->isRecordingState) {
3375 TRACE("Recording... not performing anything\n");
3379 if(oldValue == Value) {
3380 TRACE("Application is setting the old value over, nothing to do\n");
3384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3389 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3393 This, Sampler, debug_d3dsamplerstate(Type), Type);
3395 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3396 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3399 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3400 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3401 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3403 *Value = This->stateBlock->samplerState[Sampler][Type];
3404 TRACE("(%p) : Returning %#x\n", This, *Value);
3409 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3412 This->updateStateBlock->changed.scissorRect = TRUE;
3413 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3414 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3417 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3419 if(This->isRecordingState) {
3420 TRACE("Recording... not performing anything\n");
3424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3429 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3432 *pRect = This->updateStateBlock->scissorRect;
3433 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3437 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3439 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3441 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3443 This->updateStateBlock->vertexDecl = pDecl;
3444 This->updateStateBlock->changed.vertexDecl = TRUE;
3446 if (This->isRecordingState) {
3447 TRACE("Recording... not performing anything\n");
3449 } else if(pDecl == oldDecl) {
3450 /* Checked after the assignment to allow proper stateblock recording */
3451 TRACE("Application is setting the old declaration over, nothing to do\n");
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3459 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3464 *ppDecl = This->stateBlock->vertexDecl;
3465 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3469 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3471 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3473 This->updateStateBlock->vertexShader = pShader;
3474 This->updateStateBlock->changed.vertexShader = TRUE;
3476 if (This->isRecordingState) {
3477 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3478 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3479 TRACE("Recording... not performing anything\n");
3481 } else if(oldShader == pShader) {
3482 /* Checked here to allow proper stateblock recording */
3483 TRACE("App is setting the old shader over, nothing to do\n");
3487 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3488 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3489 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3496 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 if (NULL == ppShader) {
3500 return WINED3DERR_INVALIDCALL;
3502 *ppShader = This->stateBlock->vertexShader;
3503 if( NULL != *ppShader)
3504 IWineD3DVertexShader_AddRef(*ppShader);
3506 TRACE("(%p) : returning %p\n", This, *ppShader);
3510 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3511 IWineD3DDevice *iface,
3513 CONST BOOL *srcData,
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int i, cnt = min(count, MAX_CONST_B - start);
3519 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3520 iface, srcData, start, count);
3522 if (srcData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3526 for (i = 0; i < cnt; i++)
3527 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3529 for (i = start; i < cnt + start; ++i) {
3530 This->updateStateBlock->changed.vertexShaderConstantsB |= (1 << i);
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3538 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3539 IWineD3DDevice *iface,
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 int cnt = min(count, MAX_CONST_B - start);
3547 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3548 iface, dstData, start, count);
3550 if (dstData == NULL || cnt < 0)
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3558 IWineD3DDevice *iface,
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3564 int i, cnt = min(count, MAX_CONST_I - start);
3566 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3567 iface, srcData, start, count);
3569 if (srcData == NULL || cnt < 0)
3570 return WINED3DERR_INVALIDCALL;
3572 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3573 for (i = 0; i < cnt; i++)
3574 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3575 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3577 for (i = start; i < cnt + start; ++i) {
3578 This->updateStateBlock->changed.vertexShaderConstantsI |= (1 << i);
3581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3586 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3587 IWineD3DDevice *iface,
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3593 int cnt = min(count, MAX_CONST_I - start);
3595 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3596 iface, dstData, start, count);
3598 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3599 return WINED3DERR_INVALIDCALL;
3601 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3605 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3606 IWineD3DDevice *iface,
3608 CONST float *srcData,
3611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3614 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3615 iface, srcData, start, count);
3617 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3618 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3619 return WINED3DERR_INVALIDCALL;
3621 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3623 for (i = 0; i < count; i++)
3624 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3625 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3628 for (i = start; i < count + start; ++i) {
3629 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3630 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3631 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3632 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3633 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3635 ptr->idx[ptr->count++] = i;
3636 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3645 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3646 IWineD3DDevice *iface,
3648 CONST float *srcData,
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3654 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3655 iface, srcData, start, count);
3657 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3658 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3659 return WINED3DERR_INVALIDCALL;
3661 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3663 for (i = 0; i < count; i++)
3664 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3665 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3668 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3669 * context. On a context switch the old context will be fully dirtified
3671 memset(This->activeContext->vshader_const_dirty + start, 1,
3672 sizeof(*This->activeContext->vshader_const_dirty) * count);
3673 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3680 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3681 IWineD3DDevice *iface,
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3689 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3690 iface, dstData, start, count);
3692 if (dstData == NULL || cnt < 0)
3693 return WINED3DERR_INVALIDCALL;
3695 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3699 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3701 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3706 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3707 int i = This->rev_tex_unit_map[unit];
3708 int j = This->texUnitMap[stage];
3710 This->texUnitMap[stage] = unit;
3711 if (i != -1 && i != stage) {
3712 This->texUnitMap[i] = -1;
3715 This->rev_tex_unit_map[unit] = stage;
3716 if (j != -1 && j != unit) {
3717 This->rev_tex_unit_map[j] = -1;
3721 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3724 for (i = 0; i < MAX_TEXTURES; ++i) {
3725 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3726 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3727 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3728 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3729 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3730 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3731 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3732 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3734 if (color_op == WINED3DTOP_DISABLE) {
3735 /* Not used, and disable higher stages */
3736 while (i < MAX_TEXTURES) {
3737 This->fixed_function_usage_map[i] = FALSE;
3743 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3744 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3745 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3746 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3747 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3748 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3749 This->fixed_function_usage_map[i] = TRUE;
3751 This->fixed_function_usage_map[i] = FALSE;
3754 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3755 This->fixed_function_usage_map[i+1] = TRUE;
3760 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3763 device_update_fixed_function_usage_map(This);
3765 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3766 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3767 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3768 if (!This->fixed_function_usage_map[i]) continue;
3770 if (This->texUnitMap[i] != i) {
3771 device_map_stage(This, i, i);
3772 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3773 markTextureStagesDirty(This, i);
3779 /* Now work out the mapping */
3781 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3782 if (!This->fixed_function_usage_map[i]) continue;
3784 if (This->texUnitMap[i] != tex) {
3785 device_map_stage(This, i, tex);
3786 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3787 markTextureStagesDirty(This, i);
3794 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3795 const DWORD *sampler_tokens =
3796 ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3799 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3800 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3801 device_map_stage(This, i, i);
3802 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3803 if (i < MAX_TEXTURES) {
3804 markTextureStagesDirty(This, i);
3810 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, const DWORD *pshader_sampler_tokens,
3811 const DWORD *vshader_sampler_tokens, int unit)
3813 int current_mapping = This->rev_tex_unit_map[unit];
3815 if (current_mapping == -1) {
3816 /* Not currently used */
3820 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3821 /* Used by a fragment sampler */
3823 if (!pshader_sampler_tokens) {
3824 /* No pixel shader, check fixed function */
3825 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3828 /* Pixel shader, check the shader's sampler map */
3829 return !pshader_sampler_tokens[current_mapping];
3832 /* Used by a vertex sampler */
3833 return !vshader_sampler_tokens[current_mapping];
3836 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3837 const DWORD *vshader_sampler_tokens =
3838 ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3839 const DWORD *pshader_sampler_tokens = NULL;
3840 int start = GL_LIMITS(combined_samplers) - 1;
3844 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3846 /* Note that we only care if a sampler is sampled or not, not the sampler's specific type.
3847 * Otherwise we'd need to call shader_update_samplers() here for 1.x pixelshaders. */
3848 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3851 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3852 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3853 if (vshader_sampler_tokens[i]) {
3854 if (This->texUnitMap[vsampler_idx] != -1) {
3855 /* Already mapped somewhere */
3859 while (start >= 0) {
3860 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3861 device_map_stage(This, vsampler_idx, start);
3862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3874 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3875 BOOL vs = use_vs(This);
3876 BOOL ps = use_ps(This);
3879 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3880 * that would be really messy and require shader recompilation
3881 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3882 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3885 device_map_psamplers(This);
3887 device_map_fixed_function_samplers(This);
3891 device_map_vsamplers(This, ps);
3895 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3898 This->updateStateBlock->pixelShader = pShader;
3899 This->updateStateBlock->changed.pixelShader = TRUE;
3901 /* Handle recording of state blocks */
3902 if (This->isRecordingState) {
3903 TRACE("Recording... not performing anything\n");
3906 if (This->isRecordingState) {
3907 TRACE("Recording... not performing anything\n");
3908 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3909 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3913 if(pShader == oldShader) {
3914 TRACE("App is setting the old pixel shader over, nothing to do\n");
3918 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3919 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3921 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3927 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3930 if (NULL == ppShader) {
3931 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3932 return WINED3DERR_INVALIDCALL;
3935 *ppShader = This->stateBlock->pixelShader;
3936 if (NULL != *ppShader) {
3937 IWineD3DPixelShader_AddRef(*ppShader);
3939 TRACE("(%p) : returning %p\n", This, *ppShader);
3943 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3944 IWineD3DDevice *iface,
3946 CONST BOOL *srcData,
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 int i, cnt = min(count, MAX_CONST_B - start);
3952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3953 iface, srcData, start, count);
3955 if (srcData == NULL || cnt < 0)
3956 return WINED3DERR_INVALIDCALL;
3958 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3959 for (i = 0; i < cnt; i++)
3960 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3962 for (i = start; i < cnt + start; ++i) {
3963 This->updateStateBlock->changed.pixelShaderConstantsB |= (1 << i);
3966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3971 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3972 IWineD3DDevice *iface,
3977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 int cnt = min(count, MAX_CONST_B - start);
3980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3981 iface, dstData, start, count);
3983 if (dstData == NULL || cnt < 0)
3984 return WINED3DERR_INVALIDCALL;
3986 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3990 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3991 IWineD3DDevice *iface,
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3997 int i, cnt = min(count, MAX_CONST_I - start);
3999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4000 iface, srcData, start, count);
4002 if (srcData == NULL || cnt < 0)
4003 return WINED3DERR_INVALIDCALL;
4005 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4006 for (i = 0; i < cnt; i++)
4007 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4008 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4010 for (i = start; i < cnt + start; ++i) {
4011 This->updateStateBlock->changed.pixelShaderConstantsI |= (1 << i);
4014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4019 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4020 IWineD3DDevice *iface,
4025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4026 int cnt = min(count, MAX_CONST_I - start);
4028 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4029 iface, dstData, start, count);
4031 if (dstData == NULL || cnt < 0)
4032 return WINED3DERR_INVALIDCALL;
4034 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4038 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4039 IWineD3DDevice *iface,
4041 CONST float *srcData,
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4047 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4048 iface, srcData, start, count);
4050 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4051 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4052 return WINED3DERR_INVALIDCALL;
4054 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4056 for (i = 0; i < count; i++)
4057 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4058 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4061 for (i = start; i < count + start; ++i) {
4062 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4063 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4064 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4065 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4066 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4068 ptr->idx[ptr->count++] = i;
4069 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4078 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4079 IWineD3DDevice *iface,
4081 CONST float *srcData,
4084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4087 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4088 iface, srcData, start, count);
4090 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4091 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4092 return WINED3DERR_INVALIDCALL;
4094 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4096 for (i = 0; i < count; i++)
4097 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4098 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4101 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4102 * context. On a context switch the old context will be fully dirtified
4104 memset(This->activeContext->pshader_const_dirty + start, 1,
4105 sizeof(*This->activeContext->pshader_const_dirty) * count);
4106 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4113 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4114 IWineD3DDevice *iface,
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4122 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4123 iface, dstData, start, count);
4125 if (dstData == NULL || cnt < 0)
4126 return WINED3DERR_INVALIDCALL;
4128 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4132 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4133 static HRESULT process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount,
4134 const WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags)
4136 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4138 DWORD DestFVF = dest->fvf;
4140 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4144 if (lpStrideData->u.s.normal.lpData) {
4145 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4148 if (lpStrideData->u.s.position.lpData == NULL) {
4149 ERR("Source has no position mask\n");
4150 return WINED3DERR_INVALIDCALL;
4153 /* We might access VBOs from this code, so hold the lock */
4156 if (dest->resource.allocatedMemory == NULL) {
4157 /* This may happen if we do direct locking into a vbo. Unlikely,
4158 * but theoretically possible(ddraw processvertices test)
4160 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4161 if(!dest->resource.allocatedMemory) {
4163 ERR("Out of memory\n");
4164 return E_OUTOFMEMORY;
4168 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4169 checkGLcall("glBindBufferARB");
4170 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4172 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4174 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4175 checkGLcall("glUnmapBufferARB");
4179 /* Get a pointer into the destination vbo(create one if none exists) and
4180 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4182 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4183 dest->Flags |= VBFLAG_CREATEVBO;
4184 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4188 unsigned char extrabytes = 0;
4189 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4190 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4191 * this may write 4 extra bytes beyond the area that should be written
4193 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4194 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4195 if(!dest_conv_addr) {
4196 ERR("Out of memory\n");
4197 /* Continue without storing converted vertices */
4199 dest_conv = dest_conv_addr;
4203 * a) WINED3DRS_CLIPPING is enabled
4204 * b) WINED3DVOP_CLIP is passed
4206 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4207 static BOOL warned = FALSE;
4209 * The clipping code is not quite correct. Some things need
4210 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4211 * so disable clipping for now.
4212 * (The graphics in Half-Life are broken, and my processvertices
4213 * test crashes with IDirect3DDevice3)
4219 FIXME("Clipping is broken and disabled for now\n");
4221 } else doClip = FALSE;
4222 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4224 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4227 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4228 WINED3DTS_PROJECTION,
4230 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4231 WINED3DTS_WORLDMATRIX(0),
4234 TRACE("View mat:\n");
4235 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);
4236 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);
4237 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);
4238 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);
4240 TRACE("Proj mat:\n");
4241 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);
4242 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);
4243 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);
4244 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);
4246 TRACE("World mat:\n");
4247 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);
4248 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);
4249 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);
4250 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);
4252 /* Get the viewport */
4253 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4254 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4255 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4257 multiply_matrix(&mat,&view_mat,&world_mat);
4258 multiply_matrix(&mat,&proj_mat,&mat);
4260 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4262 for (i = 0; i < dwCount; i+= 1) {
4263 unsigned int tex_index;
4265 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4266 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4267 /* The position first */
4269 (const float *)(lpStrideData->u.s.position.lpData + i * lpStrideData->u.s.position.dwStride);
4271 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4273 /* Multiplication with world, view and projection matrix */
4274 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);
4275 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);
4276 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);
4277 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);
4279 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4281 /* WARNING: The following things are taken from d3d7 and were not yet checked
4282 * against d3d8 or d3d9!
4285 /* Clipping conditions: From msdn
4287 * A vertex is clipped if it does not match the following requirements
4291 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4293 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4294 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4299 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4300 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4303 /* "Normal" viewport transformation (not clipped)
4304 * 1) The values are divided by rhw
4305 * 2) The y axis is negative, so multiply it with -1
4306 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4307 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4308 * 4) Multiply x with Width/2 and add Width/2
4309 * 5) The same for the height
4310 * 6) Add the viewpoint X and Y to the 2D coordinates and
4311 * The minimum Z value to z
4312 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4314 * Well, basically it's simply a linear transformation into viewport
4326 z *= vp.MaxZ - vp.MinZ;
4328 x += vp.Width / 2 + vp.X;
4329 y += vp.Height / 2 + vp.Y;
4334 /* That vertex got clipped
4335 * Contrary to OpenGL it is not dropped completely, it just
4336 * undergoes a different calculation.
4338 TRACE("Vertex got clipped\n");
4345 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4346 * outside of the main vertex buffer memory. That needs some more
4351 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4354 ( (float *) dest_ptr)[0] = x;
4355 ( (float *) dest_ptr)[1] = y;
4356 ( (float *) dest_ptr)[2] = z;
4357 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4359 dest_ptr += 3 * sizeof(float);
4361 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4362 dest_ptr += sizeof(float);
4367 ( (float *) dest_conv)[0] = x * w;
4368 ( (float *) dest_conv)[1] = y * w;
4369 ( (float *) dest_conv)[2] = z * w;
4370 ( (float *) dest_conv)[3] = w;
4372 dest_conv += 3 * sizeof(float);
4374 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4375 dest_conv += sizeof(float);
4379 if (DestFVF & WINED3DFVF_PSIZE) {
4380 dest_ptr += sizeof(DWORD);
4381 if(dest_conv) dest_conv += sizeof(DWORD);
4383 if (DestFVF & WINED3DFVF_NORMAL) {
4384 const float *normal =
4385 (const float *)(lpStrideData->u.s.normal.lpData + i * lpStrideData->u.s.normal.dwStride);
4386 /* AFAIK this should go into the lighting information */
4387 FIXME("Didn't expect the destination to have a normal\n");
4388 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4390 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4394 if (DestFVF & WINED3DFVF_DIFFUSE) {
4395 const DWORD *color_d =
4396 (const DWORD *)(lpStrideData->u.s.diffuse.lpData + i * lpStrideData->u.s.diffuse.dwStride);
4398 static BOOL warned = FALSE;
4401 ERR("No diffuse color in source, but destination has one\n");
4405 *( (DWORD *) dest_ptr) = 0xffffffff;
4406 dest_ptr += sizeof(DWORD);
4409 *( (DWORD *) dest_conv) = 0xffffffff;
4410 dest_conv += sizeof(DWORD);
4414 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4416 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4417 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4418 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4419 dest_conv += sizeof(DWORD);
4424 if (DestFVF & WINED3DFVF_SPECULAR) {
4425 /* What's the color value in the feedback buffer? */
4426 const DWORD *color_s =
4427 (const DWORD *)(lpStrideData->u.s.specular.lpData + i * lpStrideData->u.s.specular.dwStride);
4429 static BOOL warned = FALSE;
4432 ERR("No specular color in source, but destination has one\n");
4436 *( (DWORD *) dest_ptr) = 0xFF000000;
4437 dest_ptr += sizeof(DWORD);
4440 *( (DWORD *) dest_conv) = 0xFF000000;
4441 dest_conv += sizeof(DWORD);
4445 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4447 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4448 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4449 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4450 dest_conv += sizeof(DWORD);
4455 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4456 const float *tex_coord =
4457 (const float *)(lpStrideData->u.s.texCoords[tex_index].lpData +
4458 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4460 ERR("No source texture, but destination requests one\n");
4461 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4462 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4465 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4467 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4474 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4475 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4476 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4477 dwCount * get_flexible_vertex_size(DestFVF),
4479 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4480 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4487 #undef copy_and_next
4489 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4490 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4491 WineDirect3DVertexStridedData strided;
4492 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4493 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4496 ERR("Output vertex declaration not implemented yet\n");
4499 /* Need any context to write to the vbo. */
4500 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4502 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4503 * control the streamIsUP flag, thus restore it afterwards.
4505 This->stateBlock->streamIsUP = FALSE;
4506 memset(&strided, 0, sizeof(strided));
4507 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4508 This->stateBlock->streamIsUP = streamWasUP;
4510 if(vbo || SrcStartIndex) {
4512 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4513 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4515 * Also get the start index in, but only loop over all elements if there's something to add at all.
4517 #define FIXSRC(type) \
4518 if(strided.u.s.type.VBO) { \
4519 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4520 strided.u.s.type.VBO = 0; \
4521 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4523 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4527 if(strided.u.s.type.lpData) { \
4528 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4531 FIXSRC(blendWeights);
4532 FIXSRC(blendMatrixIndices);
4537 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4538 FIXSRC(texCoords[i]);
4551 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4555 * Get / Set Texture Stage States
4556 * TODO: Verify against dx9 definitions
4558 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4559 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4560 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4562 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4564 if (Stage >= MAX_TEXTURES) {
4565 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4569 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4570 This->updateStateBlock->textureState[Stage][Type] = Value;
4572 if (This->isRecordingState) {
4573 TRACE("Recording... not performing anything\n");
4577 /* Checked after the assignments to allow proper stateblock recording */
4578 if(oldValue == Value) {
4579 TRACE("App is setting the old value over, nothing to do\n");
4583 if(Stage > This->stateBlock->lowest_disabled_stage &&
4584 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4585 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4586 * Changes in other states are important on disabled stages too
4591 if(Type == WINED3DTSS_COLOROP) {
4594 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4595 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4596 * they have to be disabled
4598 * The current stage is dirtified below.
4600 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4601 TRACE("Additionally dirtifying stage %d\n", i);
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4604 This->stateBlock->lowest_disabled_stage = Stage;
4605 TRACE("New lowest disabled: %d\n", Stage);
4606 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4607 /* Previously disabled stage enabled. Stages above it may need enabling
4608 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4609 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4611 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4614 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4615 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4618 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4619 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4621 This->stateBlock->lowest_disabled_stage = i;
4622 TRACE("New lowest disabled: %d\n", i);
4626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4631 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4632 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4633 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4634 *pValue = This->updateStateBlock->textureState[Stage][Type];
4641 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4643 IWineD3DBaseTexture *oldTexture;
4645 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4647 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4648 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4651 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4652 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4653 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4656 oldTexture = This->updateStateBlock->textures[Stage];
4658 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH */
4659 if (pTexture && ((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH)
4661 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4662 return WINED3DERR_INVALIDCALL;
4665 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4666 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4668 This->updateStateBlock->changed.textures[Stage] = TRUE;
4669 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4670 This->updateStateBlock->textures[Stage] = pTexture;
4672 /* Handle recording of state blocks */
4673 if (This->isRecordingState) {
4674 TRACE("Recording... not performing anything\n");
4678 if(oldTexture == pTexture) {
4679 TRACE("App is setting the same texture again, nothing to do\n");
4683 /** NOTE: MSDN says that setTexture increases the reference count,
4684 * and that the application must set the texture back to null (or have a leaky application),
4685 * This means we should pass the refcount up to the parent
4686 *******************************/
4687 if (NULL != This->updateStateBlock->textures[Stage]) {
4688 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4689 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4691 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4692 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4693 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4694 * so the COLOROP and ALPHAOP have to be dirtified.
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4699 if(bindCount == 1) {
4700 new->baseTexture.sampler = Stage;
4702 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4706 if (NULL != oldTexture) {
4707 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4708 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4710 IWineD3DBaseTexture_Release(oldTexture);
4711 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4716 if(bindCount && old->baseTexture.sampler == Stage) {
4718 /* Have to do a search for the other sampler(s) where the texture is bound to
4719 * Shouldn't happen as long as apps bind a texture only to one stage
4721 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4722 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4723 if(This->updateStateBlock->textures[i] == oldTexture) {
4724 old->baseTexture.sampler = i;
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4736 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4741 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4742 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4745 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4746 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4747 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4750 *ppTexture=This->stateBlock->textures[Stage];
4752 IWineD3DBaseTexture_AddRef(*ppTexture);
4754 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4762 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4763 IWineD3DSurface **ppBackBuffer) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 IWineD3DSwapChain *swapChain;
4768 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4770 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4771 if (hr == WINED3D_OK) {
4772 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4773 IWineD3DSwapChain_Release(swapChain);
4775 *ppBackBuffer = NULL;
4780 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 WARN("(%p) : stub, calling idirect3d for now\n", This);
4783 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4786 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 IWineD3DSwapChain *swapChain;
4791 if(iSwapChain > 0) {
4792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4793 if (hr == WINED3D_OK) {
4794 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4795 IWineD3DSwapChain_Release(swapChain);
4797 FIXME("(%p) Error getting display mode\n", This);
4800 /* Don't read the real display mode,
4801 but return the stored mode instead. X11 can't change the color
4802 depth, and some apps are pretty angry if they SetDisplayMode from
4803 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4805 Also don't relay to the swapchain because with ddraw it's possible
4806 that there isn't a swapchain at all */
4807 pMode->Width = This->ddraw_width;
4808 pMode->Height = This->ddraw_height;
4809 pMode->Format = This->ddraw_format;
4810 pMode->RefreshRate = 0;
4818 * Stateblock related functions
4821 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 IWineD3DStateBlockImpl *object;
4824 HRESULT temp_result;
4827 TRACE("(%p)\n", This);
4829 if (This->isRecordingState) {
4830 return WINED3DERR_INVALIDCALL;
4833 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4834 if (NULL == object ) {
4835 FIXME("(%p)Error allocating memory for stateblock\n", This);
4836 return E_OUTOFMEMORY;
4838 TRACE("(%p) created object %p\n", This, object);
4839 object->wineD3DDevice= This;
4840 /** FIXME: object->parent = parent; **/
4841 object->parent = NULL;
4842 object->blockType = WINED3DSBT_RECORDED;
4844 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4846 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4847 list_init(&object->lightMap[i]);
4850 temp_result = allocate_shader_constants(object);
4851 if (WINED3D_OK != temp_result)
4854 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4855 This->updateStateBlock = object;
4856 This->isRecordingState = TRUE;
4858 TRACE("(%p) recording stateblock %p\n",This , object);
4862 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4865 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4867 if (!This->isRecordingState) {
4868 FIXME("(%p) not recording! returning error\n", This);
4869 *ppStateBlock = NULL;
4870 return WINED3DERR_INVALIDCALL;
4873 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4874 if(object->changed.renderState[i]) {
4875 object->contained_render_states[object->num_contained_render_states] = i;
4876 object->num_contained_render_states++;
4879 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4880 if(object->changed.transform[i]) {
4881 object->contained_transform_states[object->num_contained_transform_states] = i;
4882 object->num_contained_transform_states++;
4885 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4886 if(object->changed.vertexShaderConstantsF[i]) {
4887 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4888 object->num_contained_vs_consts_f++;
4891 for(i = 0; i < MAX_CONST_I; i++) {
4892 if (object->changed.vertexShaderConstantsI & (1 << i))
4894 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4895 object->num_contained_vs_consts_i++;
4898 for(i = 0; i < MAX_CONST_B; i++) {
4899 if (object->changed.vertexShaderConstantsB & (1 << i))
4901 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4902 object->num_contained_vs_consts_b++;
4905 for(i = 0; i < MAX_CONST_I; i++) {
4906 if (object->changed.pixelShaderConstantsI & (1 << i))
4908 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4909 object->num_contained_ps_consts_i++;
4912 for(i = 0; i < MAX_CONST_B; i++) {
4913 if (object->changed.pixelShaderConstantsB & (1 << i))
4915 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4916 object->num_contained_ps_consts_b++;
4919 for(i = 0; i < MAX_TEXTURES; i++) {
4920 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4921 if(object->changed.textureState[i][j]) {
4922 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4923 object->contained_tss_states[object->num_contained_tss_states].state = j;
4924 object->num_contained_tss_states++;
4928 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4929 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4930 if(object->changed.samplerState[i][j]) {
4931 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4932 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4933 object->num_contained_sampler_states++;
4938 *ppStateBlock = (IWineD3DStateBlock*) object;
4939 This->isRecordingState = FALSE;
4940 This->updateStateBlock = This->stateBlock;
4941 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4942 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4943 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4948 * Scene related functions
4950 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4951 /* At the moment we have no need for any functionality at the beginning
4953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4954 TRACE("(%p)\n", This);
4957 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4958 return WINED3DERR_INVALIDCALL;
4960 This->inScene = TRUE;
4964 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4966 TRACE("(%p)\n", This);
4968 if(!This->inScene) {
4969 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4970 return WINED3DERR_INVALIDCALL;
4973 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4974 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4976 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4980 This->inScene = FALSE;
4984 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4985 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4986 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4987 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4988 IWineD3DSwapChain *swapChain = NULL;
4990 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4992 TRACE("(%p) Presenting the frame\n", This);
4994 for(i = 0 ; i < swapchains ; i ++) {
4996 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4997 TRACE("presentinng chain %d, %p\n", i, swapChain);
4998 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4999 IWineD3DSwapChain_Release(swapChain);
5005 /* Not called from the VTable (internal subroutine) */
5006 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5007 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5008 float Z, DWORD Stencil) {
5009 GLbitfield glMask = 0;
5011 WINED3DRECT curRect;
5013 const WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5014 UINT drawable_width, drawable_height;
5015 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5016 IWineD3DSwapChainImpl *swapchain = NULL;
5018 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5019 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5020 * for the cleared parts, and the untouched parts.
5022 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5023 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5024 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5025 * checking all this if the dest surface is in the drawable anyway.
5027 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5029 if(vp->X != 0 || vp->Y != 0 ||
5030 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5031 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5034 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5035 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5036 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5037 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5038 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5041 if(Count > 0 && pRects && (
5042 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5043 pRects[0].x2 < target->currentDesc.Width ||
5044 pRects[0].y2 < target->currentDesc.Height)) {
5045 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5052 target->get_drawable_size(target, &drawable_width, &drawable_height);
5054 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5057 /* Only set the values up once, as they are not changing */
5058 if (Flags & WINED3DCLEAR_STENCIL) {
5059 glClearStencil(Stencil);
5060 checkGLcall("glClearStencil");
5061 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5062 glStencilMask(0xFFFFFFFF);
5065 if (Flags & WINED3DCLEAR_ZBUFFER) {
5066 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5067 glDepthMask(GL_TRUE);
5069 checkGLcall("glClearDepth");
5070 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5073 if (vp->X != 0 || vp->Y != 0 ||
5074 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5075 surface_load_ds_location(This->stencilBufferTarget, location);
5077 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5078 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5079 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5080 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5081 surface_load_ds_location(This->stencilBufferTarget, location);
5083 else if (Count > 0 && pRects && (
5084 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5085 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5086 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5087 surface_load_ds_location(This->stencilBufferTarget, location);
5091 if (Flags & WINED3DCLEAR_TARGET) {
5092 TRACE("Clearing screen with glClear to color %x\n", Color);
5093 glClearColor(D3DCOLOR_R(Color),
5097 checkGLcall("glClearColor");
5099 /* Clear ALL colors! */
5100 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5101 glMask = glMask | GL_COLOR_BUFFER_BIT;
5104 vp_rect.left = vp->X;
5105 vp_rect.top = vp->Y;
5106 vp_rect.right = vp->X + vp->Width;
5107 vp_rect.bottom = vp->Y + vp->Height;
5108 if (!(Count > 0 && pRects)) {
5109 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5110 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5112 if(This->render_offscreen) {
5113 glScissor(vp_rect.left, vp_rect.top,
5114 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5116 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5117 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5119 checkGLcall("glScissor");
5121 checkGLcall("glClear");
5123 /* Now process each rect in turn */
5124 for (i = 0; i < Count; i++) {
5125 /* Note gl uses lower left, width/height */
5126 IntersectRect((RECT *)&curRect, &vp_rect, (const RECT *)&pRects[i]);
5127 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5128 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5130 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5131 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5132 curRect.x1, (target->currentDesc.Height - curRect.y2),
5133 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5135 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5136 * The rectangle is not cleared, no error is returned, but further rectanlges are
5137 * still cleared if they are valid
5139 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5140 TRACE("Rectangle with negative dimensions, ignoring\n");
5144 if(This->render_offscreen) {
5145 glScissor(curRect.x1, curRect.y1,
5146 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5148 glScissor(curRect.x1, drawable_height - curRect.y2,
5149 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5151 checkGLcall("glScissor");
5154 checkGLcall("glClear");
5158 /* Restore the old values (why..?) */
5159 if (Flags & WINED3DCLEAR_STENCIL) {
5160 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5162 if (Flags & WINED3DCLEAR_TARGET) {
5163 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5164 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5165 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5166 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5167 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5169 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5170 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5172 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5174 if (Flags & WINED3DCLEAR_ZBUFFER) {
5175 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5176 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5177 surface_modify_ds_location(This->stencilBufferTarget, location);
5182 if (SUCCEEDED(IWineD3DSurface_GetContainer((IWineD3DSurface *)target, &IID_IWineD3DSwapChain, (void **)&swapchain))) {
5183 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5186 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5192 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5193 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5194 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5195 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5197 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5198 Count, pRects, Flags, Color, Z, Stencil);
5200 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5201 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5202 /* TODO: What about depth stencil buffers without stencil bits? */
5203 return WINED3DERR_INVALIDCALL;
5206 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5212 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5213 UINT PrimitiveCount) {
5215 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5217 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5218 debug_d3dprimitivetype(PrimitiveType),
5219 StartVertex, PrimitiveCount);
5221 if(!This->stateBlock->vertexDecl) {
5222 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5223 return WINED3DERR_INVALIDCALL;
5226 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5227 if(This->stateBlock->streamIsUP) {
5228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5229 This->stateBlock->streamIsUP = FALSE;
5232 if(This->stateBlock->loadBaseVertexIndex != 0) {
5233 This->stateBlock->loadBaseVertexIndex = 0;
5234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5236 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5237 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5238 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5242 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5243 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5244 WINED3DPRIMITIVETYPE PrimitiveType,
5245 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5249 IWineD3DIndexBuffer *pIB;
5250 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5253 pIB = This->stateBlock->pIndexData;
5255 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5256 * without an index buffer set. (The first time at least...)
5257 * D3D8 simply dies, but I doubt it can do much harm to return
5258 * D3DERR_INVALIDCALL there as well. */
5259 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5260 return WINED3DERR_INVALIDCALL;
5263 if(!This->stateBlock->vertexDecl) {
5264 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5265 return WINED3DERR_INVALIDCALL;
5268 if(This->stateBlock->streamIsUP) {
5269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5270 This->stateBlock->streamIsUP = FALSE;
5272 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5274 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5275 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5276 minIndex, NumVertices, startIndex, primCount);
5278 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5279 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5285 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5286 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5287 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5290 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5291 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5296 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5297 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5298 UINT VertexStreamZeroStride) {
5299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5300 IWineD3DVertexBuffer *vb;
5302 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5303 debug_d3dprimitivetype(PrimitiveType),
5304 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5306 if(!This->stateBlock->vertexDecl) {
5307 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5308 return WINED3DERR_INVALIDCALL;
5311 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5312 vb = This->stateBlock->streamSource[0];
5313 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5314 if(vb) IWineD3DVertexBuffer_Release(vb);
5315 This->stateBlock->streamOffset[0] = 0;
5316 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5317 This->stateBlock->streamIsUP = TRUE;
5318 This->stateBlock->loadBaseVertexIndex = 0;
5320 /* TODO: Only mark dirty if drawing from a different UP address */
5321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5323 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5324 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5326 /* MSDN specifies stream zero settings must be set to NULL */
5327 This->stateBlock->streamStride[0] = 0;
5328 This->stateBlock->streamSource[0] = NULL;
5330 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5331 * the new stream sources or use UP drawing again
5336 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5337 UINT MinVertexIndex, UINT NumVertices,
5338 UINT PrimitiveCount, CONST void* pIndexData,
5339 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5340 UINT VertexStreamZeroStride) {
5342 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5343 IWineD3DVertexBuffer *vb;
5344 IWineD3DIndexBuffer *ib;
5346 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5347 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5348 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5349 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5351 if(!This->stateBlock->vertexDecl) {
5352 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5353 return WINED3DERR_INVALIDCALL;
5356 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5362 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5363 vb = This->stateBlock->streamSource[0];
5364 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5365 if(vb) IWineD3DVertexBuffer_Release(vb);
5366 This->stateBlock->streamIsUP = TRUE;
5367 This->stateBlock->streamOffset[0] = 0;
5368 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5370 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5371 This->stateBlock->baseVertexIndex = 0;
5372 This->stateBlock->loadBaseVertexIndex = 0;
5373 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5377 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5379 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5380 This->stateBlock->streamSource[0] = NULL;
5381 This->stateBlock->streamStride[0] = 0;
5382 ib = This->stateBlock->pIndexData;
5384 IWineD3DIndexBuffer_Release(ib);
5385 This->stateBlock->pIndexData = NULL;
5387 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5388 * SetStreamSource to specify a vertex buffer
5394 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided(IWineD3DDevice *iface,
5395 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5396 const WineDirect3DVertexStridedData *DrawPrimStrideData)
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5400 /* Mark the state dirty until we have nicer tracking
5401 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5406 This->stateBlock->baseVertexIndex = 0;
5407 This->up_strided = DrawPrimStrideData;
5408 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5409 This->up_strided = NULL;
5413 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface,
5414 WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount,
5415 const WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, const void *pIndexData,
5416 WINED3DFORMAT IndexDataFormat)
5418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5419 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5421 /* Mark the state dirty until we have nicer tracking
5422 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5425 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5426 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5427 This->stateBlock->streamIsUP = TRUE;
5428 This->stateBlock->baseVertexIndex = 0;
5429 This->up_strided = DrawPrimStrideData;
5430 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5431 This->up_strided = NULL;
5435 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5436 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5437 * not callable by the app directly no parameter validation checks are needed here.
5439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5440 WINED3DLOCKED_BOX src;
5441 WINED3DLOCKED_BOX dst;
5443 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5445 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5446 * dirtification to improve loading performance.
5448 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5449 if(FAILED(hr)) return hr;
5450 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5452 IWineD3DVolume_UnlockBox(pSourceVolume);
5456 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5458 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5460 IWineD3DVolume_UnlockBox(pSourceVolume);
5462 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5467 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5468 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5470 HRESULT hr = WINED3D_OK;
5471 WINED3DRESOURCETYPE sourceType;
5472 WINED3DRESOURCETYPE destinationType;
5475 /* TODO: think about moving the code into IWineD3DBaseTexture */
5477 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5479 /* verify that the source and destination textures aren't NULL */
5480 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5481 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5482 This, pSourceTexture, pDestinationTexture);
5483 hr = WINED3DERR_INVALIDCALL;
5486 if (pSourceTexture == pDestinationTexture) {
5487 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5488 This, pSourceTexture, pDestinationTexture);
5489 hr = WINED3DERR_INVALIDCALL;
5491 /* Verify that the source and destination textures are the same type */
5492 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5493 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5495 if (sourceType != destinationType) {
5496 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5498 hr = WINED3DERR_INVALIDCALL;
5501 /* check that both textures have the identical numbers of levels */
5502 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5503 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5504 hr = WINED3DERR_INVALIDCALL;
5507 if (WINED3D_OK == hr) {
5509 /* Make sure that the destination texture is loaded */
5510 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5512 /* Update every surface level of the texture */
5513 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5515 switch (sourceType) {
5516 case WINED3DRTYPE_TEXTURE:
5518 IWineD3DSurface *srcSurface;
5519 IWineD3DSurface *destSurface;
5521 for (i = 0 ; i < levels ; ++i) {
5522 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5523 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5524 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5525 IWineD3DSurface_Release(srcSurface);
5526 IWineD3DSurface_Release(destSurface);
5527 if (WINED3D_OK != hr) {
5528 WARN("(%p) : Call to update surface failed\n", This);
5534 case WINED3DRTYPE_CUBETEXTURE:
5536 IWineD3DSurface *srcSurface;
5537 IWineD3DSurface *destSurface;
5538 WINED3DCUBEMAP_FACES faceType;
5540 for (i = 0 ; i < levels ; ++i) {
5541 /* Update each cube face */
5542 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5543 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5544 if (WINED3D_OK != hr) {
5545 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5547 TRACE("Got srcSurface %p\n", srcSurface);
5549 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5550 if (WINED3D_OK != hr) {
5551 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5553 TRACE("Got desrSurface %p\n", destSurface);
5555 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5556 IWineD3DSurface_Release(srcSurface);
5557 IWineD3DSurface_Release(destSurface);
5558 if (WINED3D_OK != hr) {
5559 WARN("(%p) : Call to update surface failed\n", This);
5567 case WINED3DRTYPE_VOLUMETEXTURE:
5569 IWineD3DVolume *srcVolume = NULL;
5570 IWineD3DVolume *destVolume = NULL;
5572 for (i = 0 ; i < levels ; ++i) {
5573 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5574 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5575 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5576 IWineD3DVolume_Release(srcVolume);
5577 IWineD3DVolume_Release(destVolume);
5578 if (WINED3D_OK != hr) {
5579 WARN("(%p) : Call to update volume failed\n", This);
5587 FIXME("(%p) : Unsupported source and destination type\n", This);
5588 hr = WINED3DERR_INVALIDCALL;
5595 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5596 IWineD3DSwapChain *swapChain;
5598 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5599 if(hr == WINED3D_OK) {
5600 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5601 IWineD3DSwapChain_Release(swapChain);
5606 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5607 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5608 IWineD3DBaseTextureImpl *texture;
5609 const struct GlPixelFormatDesc *gl_info;
5612 TRACE("(%p) : %p\n", This, pNumPasses);
5614 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5615 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5616 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5617 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5619 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5620 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5621 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5624 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5625 if(!texture) continue;
5626 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5627 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5629 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5630 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5633 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5634 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5637 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5638 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5639 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5644 /* return a sensible default */
5647 TRACE("returning D3D_OK\n");
5651 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5655 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5656 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5657 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5658 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5663 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5667 PALETTEENTRY **palettes;
5669 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5671 if (PaletteNumber >= MAX_PALETTES) {
5672 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5673 return WINED3DERR_INVALIDCALL;
5676 if (PaletteNumber >= This->NumberOfPalettes) {
5677 NewSize = This->NumberOfPalettes;
5680 } while(PaletteNumber >= NewSize);
5681 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5683 ERR("Out of memory!\n");
5684 return E_OUTOFMEMORY;
5686 This->palettes = palettes;
5687 This->NumberOfPalettes = NewSize;
5690 if (!This->palettes[PaletteNumber]) {
5691 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5692 if (!This->palettes[PaletteNumber]) {
5693 ERR("Out of memory!\n");
5694 return E_OUTOFMEMORY;
5698 for (j = 0; j < 256; ++j) {
5699 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5700 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5701 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5702 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5704 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5705 TRACE("(%p) : returning\n", This);
5709 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5712 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5713 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5714 /* What happens in such situation isn't documented; Native seems to silently abort
5715 on such conditions. Return Invalid Call. */
5716 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5717 return WINED3DERR_INVALIDCALL;
5719 for (j = 0; j < 256; ++j) {
5720 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5721 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5722 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5723 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5725 TRACE("(%p) : returning\n", This);
5729 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5730 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5731 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5732 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5733 (tested with reference rasterizer). Return Invalid Call. */
5734 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5735 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5736 return WINED3DERR_INVALIDCALL;
5738 /*TODO: stateblocks */
5739 if (This->currentPalette != PaletteNumber) {
5740 This->currentPalette = PaletteNumber;
5741 dirtify_p8_texture_samplers(This);
5743 TRACE("(%p) : returning\n", This);
5747 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5748 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5749 if (PaletteNumber == NULL) {
5750 WARN("(%p) : returning Invalid Call\n", This);
5751 return WINED3DERR_INVALIDCALL;
5753 /*TODO: stateblocks */
5754 *PaletteNumber = This->currentPalette;
5755 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5759 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 FIXME("(%p) : stub\n", This);
5768 This->softwareVertexProcessing = bSoftware;
5773 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5774 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5778 FIXME("(%p) : stub\n", This);
5781 return This->softwareVertexProcessing;
5785 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5787 IWineD3DSwapChain *swapChain;
5790 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5793 if(hr == WINED3D_OK){
5794 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5795 IWineD3DSwapChain_Release(swapChain);
5797 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5803 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5806 if(nSegments != 0.0f) {
5809 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5816 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5817 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5821 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5827 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5828 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5829 /** TODO: remove casts to IWineD3DSurfaceImpl
5830 * NOTE: move code to surface to accomplish this
5831 ****************************************/
5832 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5833 int srcWidth, srcHeight;
5834 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5835 WINED3DFORMAT destFormat, srcFormat;
5837 int srcLeft, destLeft, destTop;
5838 WINED3DPOOL srcPool, destPool;
5840 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5841 glDescriptor *glDescription = NULL;
5845 CONVERT_TYPES convert = NO_CONVERSION;
5847 WINED3DSURFACE_DESC winedesc;
5849 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5850 memset(&winedesc, 0, sizeof(winedesc));
5851 winedesc.Width = &srcSurfaceWidth;
5852 winedesc.Height = &srcSurfaceHeight;
5853 winedesc.Pool = &srcPool;
5854 winedesc.Format = &srcFormat;
5856 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5858 winedesc.Width = &destSurfaceWidth;
5859 winedesc.Height = &destSurfaceHeight;
5860 winedesc.Pool = &destPool;
5861 winedesc.Format = &destFormat;
5862 winedesc.Size = &destSize;
5864 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5866 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5867 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5868 return WINED3DERR_INVALIDCALL;
5871 /* This call loads the opengl surface directly, instead of copying the surface to the
5872 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5873 * copy in sysmem and use regular surface loading.
5875 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5876 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5877 if(convert != NO_CONVERSION) {
5878 return IWineD3DSurface_BltFast(pDestinationSurface,
5879 pDestPoint ? pDestPoint->x : 0,
5880 pDestPoint ? pDestPoint->y : 0,
5881 pSourceSurface, pSourceRect, 0);
5884 if (destFormat == WINED3DFMT_UNKNOWN) {
5885 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5886 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5888 /* Get the update surface description */
5889 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5892 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5894 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5896 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5897 checkGLcall("glActiveTextureARB");
5901 /* Make sure the surface is loaded and up to date */
5902 IWineD3DSurface_PreLoad(pDestinationSurface);
5903 IWineD3DSurface_BindTexture(pDestinationSurface);
5905 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5907 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5908 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5909 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5910 srcLeft = pSourceRect ? pSourceRect->left : 0;
5911 destLeft = pDestPoint ? pDestPoint->x : 0;
5912 destTop = pDestPoint ? pDestPoint->y : 0;
5915 /* This function doesn't support compressed textures
5916 the pitch is just bytesPerPixel * width */
5917 if(srcWidth != srcSurfaceWidth || srcLeft ){
5918 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5919 offset += srcLeft * pSrcSurface->bytesPerPixel;
5920 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5922 /* TODO DXT formats */
5924 if(pSourceRect != NULL && pSourceRect->top != 0){
5925 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5927 TRACE("(%p) glTexSubImage2D, level %d, left %d, top %d, width %d, height %d, fmt %#x, type %#x, memory %p+%#x\n",
5928 This, glDescription->level, destLeft, destTop, srcWidth, srcHeight, glDescription->glFormat,
5929 glDescription->glType, IWineD3DSurface_GetData(pSourceSurface), offset);
5932 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5934 /* need to lock the surface to get the data */
5935 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5940 /* TODO: Cube and volume support */
5942 /* not a whole row so we have to do it a line at a time */
5945 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5946 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5948 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5950 glTexSubImage2D(glDescription->target
5951 ,glDescription->level
5956 ,glDescription->glFormat
5957 ,glDescription->glType
5958 ,data /* could be quicker using */
5963 } else { /* Full width, so just write out the whole texture */
5964 const unsigned char* data = ((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5966 if (WINED3DFMT_DXT1 == destFormat ||
5967 WINED3DFMT_DXT2 == destFormat ||
5968 WINED3DFMT_DXT3 == destFormat ||
5969 WINED3DFMT_DXT4 == destFormat ||
5970 WINED3DFMT_DXT5 == destFormat) {
5971 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5972 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5973 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5974 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5975 } if (destFormat != srcFormat) {
5976 FIXME("Updating mixed format compressed texture is not curretly support\n");
5978 GL_EXTCALL(glCompressedTexImage2DARB(glDescription->target, glDescription->level,
5979 glDescription->glFormatInternal, srcWidth, srcHeight, 0, destSize, data));
5982 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5987 glTexSubImage2D(glDescription->target, glDescription->level, destLeft, destTop,
5988 srcWidth, srcHeight, glDescription->glFormat, glDescription->glType, data);
5991 checkGLcall("glTexSubImage2D");
5995 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5996 sampler = This->rev_tex_unit_map[0];
5997 if (sampler != -1) {
5998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6004 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
6005 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6006 struct WineD3DRectPatch *patch;
6010 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6012 if(!(Handle || pRectPatchInfo)) {
6013 /* TODO: Write a test for the return value, thus the FIXME */
6014 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6015 return WINED3DERR_INVALIDCALL;
6019 i = PATCHMAP_HASHFUNC(Handle);
6021 LIST_FOR_EACH(e, &This->patches[i]) {
6022 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6023 if(patch->Handle == Handle) {
6030 TRACE("Patch does not exist. Creating a new one\n");
6031 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6032 patch->Handle = Handle;
6033 list_add_head(&This->patches[i], &patch->entry);
6035 TRACE("Found existing patch %p\n", patch);
6038 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6039 * attributes we have to tesselate, read back, and draw. This needs a patch
6040 * management structure instance. Create one.
6042 * A possible improvement is to check if a vertex shader is used, and if not directly
6045 FIXME("Drawing an uncached patch. This is slow\n");
6046 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6049 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6050 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6051 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6053 TRACE("Tesselation density or patch info changed, retesselating\n");
6055 if(pRectPatchInfo) {
6056 patch->RectPatchInfo = *pRectPatchInfo;
6058 patch->numSegs[0] = pNumSegs[0];
6059 patch->numSegs[1] = pNumSegs[1];
6060 patch->numSegs[2] = pNumSegs[2];
6061 patch->numSegs[3] = pNumSegs[3];
6063 hr = tesselate_rectpatch(This, patch);
6065 WARN("Patch tesselation failed\n");
6067 /* Do not release the handle to store the params of the patch */
6069 HeapFree(GetProcessHeap(), 0, patch);
6075 This->currentPatch = patch;
6076 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6077 This->currentPatch = NULL;
6079 /* Destroy uncached patches */
6081 HeapFree(GetProcessHeap(), 0, patch->mem);
6082 HeapFree(GetProcessHeap(), 0, patch);
6087 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6088 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6089 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6090 FIXME("(%p) : Stub\n", This);
6094 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6097 struct WineD3DRectPatch *patch;
6099 TRACE("(%p) Handle(%d)\n", This, Handle);
6101 i = PATCHMAP_HASHFUNC(Handle);
6102 LIST_FOR_EACH(e, &This->patches[i]) {
6103 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6104 if(patch->Handle == Handle) {
6105 TRACE("Deleting patch %p\n", patch);
6106 list_remove(&patch->entry);
6107 HeapFree(GetProcessHeap(), 0, patch->mem);
6108 HeapFree(GetProcessHeap(), 0, patch);
6113 /* TODO: Write a test for the return value */
6114 FIXME("Attempt to destroy nonexistent patch\n");
6115 return WINED3DERR_INVALIDCALL;
6118 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6120 IWineD3DSwapChain *swapchain;
6122 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6123 if (SUCCEEDED(hr)) {
6124 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6131 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6133 IWineD3DSwapChain *swapchain;
6135 swapchain = get_swapchain(surface);
6139 TRACE("Surface %p is onscreen\n", surface);
6141 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6143 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6144 buffer = surface_get_gl_buffer(surface, swapchain);
6145 glDrawBuffer(buffer);
6146 checkGLcall("glDrawBuffer()");
6148 TRACE("Surface %p is offscreen\n", surface);
6150 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6152 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6153 context_attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6154 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6155 checkGLcall("glFramebufferRenderbufferEXT");
6159 glEnable(GL_SCISSOR_TEST);
6161 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6163 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6164 rect->x2 - rect->x1, rect->y2 - rect->y1);
6166 checkGLcall("glScissor");
6167 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6169 glDisable(GL_SCISSOR_TEST);
6171 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6173 glDisable(GL_BLEND);
6174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6176 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6177 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6179 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6180 glClear(GL_COLOR_BUFFER_BIT);
6181 checkGLcall("glClear");
6183 if (This->activeContext->current_fbo) {
6184 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6186 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6187 checkGLcall("glBindFramebuffer()");
6190 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6191 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6192 glDrawBuffer(GL_BACK);
6193 checkGLcall("glDrawBuffer()");
6199 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6200 unsigned int r, g, b, a;
6203 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6204 destfmt == WINED3DFMT_R8G8B8)
6207 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6209 a = (color & 0xff000000) >> 24;
6210 r = (color & 0x00ff0000) >> 16;
6211 g = (color & 0x0000ff00) >> 8;
6212 b = (color & 0x000000ff) >> 0;
6216 case WINED3DFMT_R5G6B5:
6217 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6224 TRACE("Returning %08x\n", ret);
6227 case WINED3DFMT_X1R5G5B5:
6228 case WINED3DFMT_A1R5G5B5:
6237 TRACE("Returning %08x\n", ret);
6241 TRACE("Returning %08x\n", a);
6244 case WINED3DFMT_X4R4G4B4:
6245 case WINED3DFMT_A4R4G4B4:
6254 TRACE("Returning %08x\n", ret);
6257 case WINED3DFMT_R3G3B2:
6264 TRACE("Returning %08x\n", ret);
6267 case WINED3DFMT_X8B8G8R8:
6268 case WINED3DFMT_A8B8G8R8:
6273 TRACE("Returning %08x\n", ret);
6276 case WINED3DFMT_A2R10G10B10:
6278 r = (r * 1024) / 256;
6279 g = (g * 1024) / 256;
6280 b = (b * 1024) / 256;
6285 TRACE("Returning %08x\n", ret);
6288 case WINED3DFMT_A2B10G10R10:
6290 r = (r * 1024) / 256;
6291 g = (g * 1024) / 256;
6292 b = (b * 1024) / 256;
6297 TRACE("Returning %08x\n", ret);
6301 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6306 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6307 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6308 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6310 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6312 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6313 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6314 return WINED3DERR_INVALIDCALL;
6317 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6318 color_fill_fbo(iface, pSurface, pRect, color);
6321 /* Just forward this to the DirectDraw blitting engine */
6322 memset(&BltFx, 0, sizeof(BltFx));
6323 BltFx.dwSize = sizeof(BltFx);
6324 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6325 return IWineD3DSurface_Blt(pSurface, (const RECT *)pRect, NULL, NULL,
6326 WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6330 /* rendertarget and depth stencil functions */
6331 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6332 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6334 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6335 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6336 return WINED3DERR_INVALIDCALL;
6339 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6340 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6341 /* Note inc ref on returned surface */
6342 if(*ppRenderTarget != NULL)
6343 IWineD3DSurface_AddRef(*ppRenderTarget);
6347 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6349 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6350 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6351 IWineD3DSwapChainImpl *Swapchain;
6354 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6356 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6357 if(hr != WINED3D_OK) {
6358 ERR("Can't get the swapchain\n");
6362 /* Make sure to release the swapchain */
6363 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6365 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6366 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6367 return WINED3DERR_INVALIDCALL;
6369 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6370 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6371 return WINED3DERR_INVALIDCALL;
6374 if(Swapchain->frontBuffer != Front) {
6375 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6377 if(Swapchain->frontBuffer)
6378 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6379 Swapchain->frontBuffer = Front;
6381 if(Swapchain->frontBuffer) {
6382 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6386 if(Back && !Swapchain->backBuffer) {
6387 /* We need memory for the back buffer array - only one back buffer this way */
6388 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6389 if(!Swapchain->backBuffer) {
6390 ERR("Out of memory\n");
6391 return E_OUTOFMEMORY;
6395 if(Swapchain->backBuffer[0] != Back) {
6396 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6398 /* What to do about the context here in the case of multithreading? Not sure.
6399 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6402 if(!Swapchain->backBuffer[0]) {
6403 /* GL was told to draw to the front buffer at creation,
6406 glDrawBuffer(GL_BACK);
6407 checkGLcall("glDrawBuffer(GL_BACK)");
6408 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6409 Swapchain->presentParms.BackBufferCount = 1;
6411 /* That makes problems - disable for now */
6412 /* glDrawBuffer(GL_FRONT); */
6413 checkGLcall("glDrawBuffer(GL_FRONT)");
6414 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6415 Swapchain->presentParms.BackBufferCount = 0;
6419 if(Swapchain->backBuffer[0])
6420 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6421 Swapchain->backBuffer[0] = Back;
6423 if(Swapchain->backBuffer[0]) {
6424 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6426 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6427 Swapchain->backBuffer = NULL;
6435 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6437 *ppZStencilSurface = This->stencilBufferTarget;
6438 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6440 if(*ppZStencilSurface != NULL) {
6441 /* Note inc ref on returned surface */
6442 IWineD3DSurface_AddRef(*ppZStencilSurface);
6445 return WINED3DERR_NOTFOUND;
6449 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6450 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip)
6452 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6453 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6454 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6456 POINT offset = {0, 0};
6458 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6459 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6460 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6461 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6464 case WINED3DTEXF_LINEAR:
6465 gl_filter = GL_LINEAR;
6469 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6470 case WINED3DTEXF_NONE:
6471 case WINED3DTEXF_POINT:
6472 gl_filter = GL_NEAREST;
6476 /* Attach src surface to src fbo */
6477 src_swapchain = get_swapchain(src_surface);
6478 if (src_swapchain) {
6479 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6481 TRACE("Source surface %p is onscreen\n", src_surface);
6482 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6483 /* Make sure the drawable is up to date. In the offscreen case
6484 * attach_surface_fbo() implicitly takes care of this. */
6485 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6487 if(buffer == GL_FRONT) {
6490 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6491 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6492 h = windowsize.bottom - windowsize.top;
6493 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6494 src_rect->y1 = offset.y + h - src_rect->y1;
6495 src_rect->y2 = offset.y + h - src_rect->y2;
6497 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6498 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6502 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6503 glReadBuffer(buffer);
6504 checkGLcall("glReadBuffer()");
6506 TRACE("Source surface %p is offscreen\n", src_surface);
6508 context_bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6509 context_attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6510 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6511 checkGLcall("glReadBuffer()");
6512 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6513 checkGLcall("glFramebufferRenderbufferEXT");
6517 /* Attach dst surface to dst fbo */
6518 dst_swapchain = get_swapchain(dst_surface);
6519 if (dst_swapchain) {
6520 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6522 TRACE("Destination surface %p is onscreen\n", dst_surface);
6523 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6524 /* Make sure the drawable is up to date. In the offscreen case
6525 * attach_surface_fbo() implicitly takes care of this. */
6526 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6528 if(buffer == GL_FRONT) {
6531 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6532 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6533 h = windowsize.bottom - windowsize.top;
6534 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6535 dst_rect->y1 = offset.y + h - dst_rect->y1;
6536 dst_rect->y2 = offset.y + h - dst_rect->y2;
6538 /* Screen coords = window coords, surface height = window height */
6539 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6540 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6544 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6545 glDrawBuffer(buffer);
6546 checkGLcall("glDrawBuffer()");
6548 TRACE("Destination surface %p is offscreen\n", dst_surface);
6550 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6551 if(!src_swapchain) {
6552 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6556 context_bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6557 context_attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6558 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6559 checkGLcall("glDrawBuffer()");
6560 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6561 checkGLcall("glFramebufferRenderbufferEXT");
6563 glDisable(GL_SCISSOR_TEST);
6564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6567 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6568 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6569 checkGLcall("glBlitFramebuffer()");
6571 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6572 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6573 checkGLcall("glBlitFramebuffer()");
6576 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6578 if (This->activeContext->current_fbo) {
6579 context_bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->current_fbo->id);
6581 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6582 checkGLcall("glBindFramebuffer()");
6585 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6586 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6587 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6588 glDrawBuffer(GL_BACK);
6589 checkGLcall("glDrawBuffer()");
6594 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6596 WINED3DVIEWPORT viewport;
6598 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6600 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6601 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6602 This, RenderTargetIndex, GL_LIMITS(buffers));
6603 return WINED3DERR_INVALIDCALL;
6606 /* MSDN says that null disables the render target
6607 but a device must always be associated with a render target
6608 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6610 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6611 FIXME("Trying to set render target 0 to NULL\n");
6612 return WINED3DERR_INVALIDCALL;
6614 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6615 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);
6616 return WINED3DERR_INVALIDCALL;
6619 /* If we are trying to set what we already have, don't bother */
6620 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6621 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6624 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6625 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6626 This->render_targets[RenderTargetIndex] = pRenderTarget;
6628 /* Render target 0 is special */
6629 if(RenderTargetIndex == 0) {
6630 /* Finally, reset the viewport as the MSDN states. */
6631 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6632 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6635 viewport.MaxZ = 1.0f;
6636 viewport.MinZ = 0.0f;
6637 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6638 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6639 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6646 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6648 HRESULT hr = WINED3D_OK;
6649 IWineD3DSurface *tmp;
6651 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6653 if (pNewZStencil == This->stencilBufferTarget) {
6654 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6656 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6657 * depending on the renter target implementation being used.
6658 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6659 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6660 * stencil buffer and incur an extra memory overhead
6661 ******************************************************/
6663 if (This->stencilBufferTarget) {
6664 if (((IWineD3DSwapChainImpl *)This->swapchains[0])->presentParms.Flags & WINED3DPRESENTFLAG_DISCARD_DEPTHSTENCIL
6665 || ((IWineD3DSurfaceImpl *)This->stencilBufferTarget)->Flags & SFLAG_DISCARD) {
6666 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_DISCARDED);
6668 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6669 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6670 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6674 tmp = This->stencilBufferTarget;
6675 This->stencilBufferTarget = pNewZStencil;
6676 /* should we be calling the parent or the wined3d surface? */
6677 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6678 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6681 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6682 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6692 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6693 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6695 /* TODO: the use of Impl is deprecated. */
6696 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6697 WINED3DLOCKED_RECT lockedRect;
6699 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6701 /* some basic validation checks */
6702 if(This->cursorTexture) {
6703 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6705 glDeleteTextures(1, &This->cursorTexture);
6707 This->cursorTexture = 0;
6710 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6711 This->haveHardwareCursor = TRUE;
6713 This->haveHardwareCursor = FALSE;
6716 WINED3DLOCKED_RECT rect;
6718 /* MSDN: Cursor must be A8R8G8B8 */
6719 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6720 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6721 return WINED3DERR_INVALIDCALL;
6724 /* MSDN: Cursor must be smaller than the display mode */
6725 if(pSur->currentDesc.Width > This->ddraw_width ||
6726 pSur->currentDesc.Height > This->ddraw_height) {
6727 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);
6728 return WINED3DERR_INVALIDCALL;
6731 if (!This->haveHardwareCursor) {
6732 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6734 /* Do not store the surface's pointer because the application may
6735 * release it after setting the cursor image. Windows doesn't
6736 * addref the set surface, so we can't do this either without
6737 * creating circular refcount dependencies. Copy out the gl texture
6740 This->cursorWidth = pSur->currentDesc.Width;
6741 This->cursorHeight = pSur->currentDesc.Height;
6742 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6744 const struct GlPixelFormatDesc *glDesc;
6745 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6746 char *mem, *bits = (char *)rect.pBits;
6747 GLint intfmt = glDesc->glInternal;
6748 GLint format = glDesc->glFormat;
6749 GLint type = glDesc->glType;
6750 INT height = This->cursorHeight;
6751 INT width = This->cursorWidth;
6752 INT bpp = tableEntry->bpp;
6755 /* Reformat the texture memory (pitch and width can be
6757 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6758 for(i = 0; i < height; i++)
6759 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6760 IWineD3DSurface_UnlockRect(pCursorBitmap);
6763 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6764 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6765 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6768 /* Make sure that a proper texture unit is selected */
6769 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6770 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6771 checkGLcall("glActiveTextureARB");
6773 sampler = This->rev_tex_unit_map[0];
6774 if (sampler != -1) {
6775 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6777 /* Create a new cursor texture */
6778 glGenTextures(1, &This->cursorTexture);
6779 checkGLcall("glGenTextures");
6780 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6781 checkGLcall("glBindTexture");
6782 /* Copy the bitmap memory into the cursor texture */
6783 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6784 HeapFree(GetProcessHeap(), 0, mem);
6785 checkGLcall("glTexImage2D");
6787 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6788 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6789 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6796 FIXME("A cursor texture was not returned.\n");
6797 This->cursorTexture = 0;
6802 /* Draw a hardware cursor */
6803 ICONINFO cursorInfo;
6805 /* Create and clear maskBits because it is not needed for
6806 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6808 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6809 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6810 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6811 WINED3DLOCK_NO_DIRTY_UPDATE |
6812 WINED3DLOCK_READONLY
6814 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6815 pSur->currentDesc.Height);
6817 cursorInfo.fIcon = FALSE;
6818 cursorInfo.xHotspot = XHotSpot;
6819 cursorInfo.yHotspot = YHotSpot;
6820 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6821 pSur->currentDesc.Height, 1,
6823 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6824 pSur->currentDesc.Height, 1,
6825 32, lockedRect.pBits);
6826 IWineD3DSurface_UnlockRect(pCursorBitmap);
6827 /* Create our cursor and clean up. */
6828 cursor = CreateIconIndirect(&cursorInfo);
6830 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6831 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6832 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6833 This->hardwareCursor = cursor;
6834 HeapFree(GetProcessHeap(), 0, maskBits);
6838 This->xHotSpot = XHotSpot;
6839 This->yHotSpot = YHotSpot;
6843 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6844 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6845 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6847 This->xScreenSpace = XScreenSpace;
6848 This->yScreenSpace = YScreenSpace;
6854 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6856 BOOL oldVisible = This->bCursorVisible;
6859 TRACE("(%p) : visible(%d)\n", This, bShow);
6862 * When ShowCursor is first called it should make the cursor appear at the OS's last
6863 * known cursor position. Because of this, some applications just repetitively call
6864 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6867 This->xScreenSpace = pt.x;
6868 This->yScreenSpace = pt.y;
6870 if (This->haveHardwareCursor) {
6871 This->bCursorVisible = bShow;
6873 SetCursor(This->hardwareCursor);
6879 if (This->cursorTexture)
6880 This->bCursorVisible = bShow;
6886 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
6887 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6888 IWineD3DResourceImpl *resource;
6889 TRACE("(%p) : state (%u)\n", This, This->state);
6891 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
6892 switch (This->state) {
6895 case WINED3DERR_DEVICELOST:
6897 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
6898 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
6899 return WINED3DERR_DEVICENOTRESET;
6901 return WINED3DERR_DEVICELOST;
6903 case WINED3DERR_DRIVERINTERNALERROR:
6904 return WINED3DERR_DRIVERINTERNALERROR;
6908 return WINED3DERR_DRIVERINTERNALERROR;
6912 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
6913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6914 /** FIXME: Resource tracking needs to be done,
6915 * The closes we can do to this is set the priorities of all managed textures low
6916 * and then reset them.
6917 ***********************************************************/
6918 FIXME("(%p) : stub\n", This);
6922 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, const WINED3DPRESENT_PARAMETERS* pPresentationParameters)
6924 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
6926 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
6927 if(surface->Flags & SFLAG_DIBSECTION) {
6928 /* Release the DC */
6929 SelectObject(surface->hDC, surface->dib.holdbitmap);
6930 DeleteDC(surface->hDC);
6931 /* Release the DIB section */
6932 DeleteObject(surface->dib.DIBsection);
6933 surface->dib.bitmap_data = NULL;
6934 surface->resource.allocatedMemory = NULL;
6935 surface->Flags &= ~SFLAG_DIBSECTION;
6937 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
6938 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
6939 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
6940 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
6941 surface->pow2Width = pPresentationParameters->BackBufferWidth;
6942 surface->pow2Height = pPresentationParameters->BackBufferHeight;
6944 surface->pow2Width = surface->pow2Height = 1;
6945 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
6946 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
6948 surface->glRect.left = 0;
6949 surface->glRect.top = 0;
6950 surface->glRect.right = surface->pow2Width;
6951 surface->glRect.bottom = surface->pow2Height;
6953 if(surface->glDescription.textureName) {
6954 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6956 glDeleteTextures(1, &surface->glDescription.textureName);
6958 surface->glDescription.textureName = 0;
6959 surface->Flags &= ~SFLAG_CLIENT;
6961 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
6962 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
6963 surface->Flags |= SFLAG_NONPOW2;
6965 surface->Flags &= ~SFLAG_NONPOW2;
6967 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
6968 surface->resource.allocatedMemory = NULL;
6969 surface->resource.heapMemory = NULL;
6970 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
6971 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
6972 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
6973 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
6975 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
6979 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
6980 TRACE("Unloading resource %p\n", resource);
6981 IWineD3DResource_UnLoad(resource);
6982 IWineD3DResource_Release(resource);
6986 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, const WINED3DPRESENT_PARAMETERS *pp)
6989 WINED3DDISPLAYMODE m;
6992 /* All Windowed modes are supported, as is leaving the current mode */
6993 if(pp->Windowed) return TRUE;
6994 if(!pp->BackBufferWidth) return TRUE;
6995 if(!pp->BackBufferHeight) return TRUE;
6997 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
6998 for(i = 0; i < count; i++) {
6999 memset(&m, 0, sizeof(m));
7000 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7002 ERR("EnumAdapterModes failed\n");
7004 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7005 /* Mode found, it is supported */
7009 /* Mode not found -> not supported */
7013 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7014 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7015 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7017 IWineD3DBaseShaderImpl *shader;
7019 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7020 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7021 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7025 if(This->depth_blt_texture) {
7026 glDeleteTextures(1, &This->depth_blt_texture);
7027 This->depth_blt_texture = 0;
7029 if (This->depth_blt_rb) {
7030 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7031 This->depth_blt_rb = 0;
7032 This->depth_blt_rb_w = 0;
7033 This->depth_blt_rb_h = 0;
7037 This->blitter->free_private(iface);
7038 This->frag_pipe->free_private(iface);
7039 This->shader_backend->shader_free_private(iface);
7042 for (i = 0; i < GL_LIMITS(textures); i++) {
7043 /* Textures are recreated below */
7044 glDeleteTextures(1, &This->dummyTextureName[i]);
7045 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7046 This->dummyTextureName[i] = 0;
7050 while(This->numContexts) {
7051 DestroyContext(This, This->contexts[0]);
7053 This->activeContext = NULL;
7054 HeapFree(GetProcessHeap(), 0, swapchain->context);
7055 swapchain->context = NULL;
7056 swapchain->num_contexts = 0;
7059 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7061 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7063 IWineD3DSurfaceImpl *target;
7065 /* Recreate the primary swapchain's context */
7066 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7067 if(swapchain->backBuffer) {
7068 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7070 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7072 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7073 &swapchain->presentParms);
7074 swapchain->num_contexts = 1;
7075 This->activeContext = swapchain->context[0];
7077 create_dummy_textures(This);
7079 hr = This->shader_backend->shader_alloc_private(iface);
7081 ERR("Failed to recreate shader private data\n");
7084 hr = This->frag_pipe->alloc_private(iface);
7086 TRACE("Fragment pipeline private data couldn't be allocated\n");
7089 hr = This->blitter->alloc_private(iface);
7091 TRACE("Blitter private data couldn't be allocated\n");
7098 This->blitter->free_private(iface);
7099 This->frag_pipe->free_private(iface);
7100 This->shader_backend->shader_free_private(iface);
7104 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7105 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7106 IWineD3DSwapChainImpl *swapchain;
7108 BOOL DisplayModeChanged = FALSE;
7109 WINED3DDISPLAYMODE mode;
7110 TRACE("(%p)\n", This);
7112 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7114 ERR("Failed to get the first implicit swapchain\n");
7118 if(!is_display_mode_supported(This, pPresentationParameters)) {
7119 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7120 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7121 pPresentationParameters->BackBufferHeight);
7122 return WINED3DERR_INVALIDCALL;
7125 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7126 * on an existing gl context, so there's no real need for recreation.
7128 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7130 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7132 TRACE("New params:\n");
7133 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7134 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7135 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7136 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7137 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7138 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7139 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7140 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7141 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7142 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7143 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7144 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7145 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7147 /* No special treatment of these parameters. Just store them */
7148 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7149 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7150 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7151 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7153 /* What to do about these? */
7154 if(pPresentationParameters->BackBufferCount != 0 &&
7155 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7156 ERR("Cannot change the back buffer count yet\n");
7158 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7159 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7160 ERR("Cannot change the back buffer format yet\n");
7162 if(pPresentationParameters->hDeviceWindow != NULL &&
7163 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7164 ERR("Cannot change the device window yet\n");
7166 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7167 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7168 return WINED3DERR_INVALIDCALL;
7171 /* Reset the depth stencil */
7172 if (pPresentationParameters->EnableAutoDepthStencil)
7173 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7175 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7177 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7179 if(pPresentationParameters->Windowed) {
7180 mode.Width = swapchain->orig_width;
7181 mode.Height = swapchain->orig_height;
7182 mode.RefreshRate = 0;
7183 mode.Format = swapchain->presentParms.BackBufferFormat;
7185 mode.Width = pPresentationParameters->BackBufferWidth;
7186 mode.Height = pPresentationParameters->BackBufferHeight;
7187 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7188 mode.Format = swapchain->presentParms.BackBufferFormat;
7191 /* Should Width == 800 && Height == 0 set 800x600? */
7192 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7193 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7194 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7201 vp.Width = pPresentationParameters->BackBufferWidth;
7202 vp.Height = pPresentationParameters->BackBufferHeight;
7206 if(!pPresentationParameters->Windowed) {
7207 DisplayModeChanged = TRUE;
7209 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7210 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7212 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7213 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7214 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7216 if(This->auto_depth_stencil_buffer) {
7217 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7221 /* Now set the new viewport */
7222 IWineD3DDevice_SetViewport(iface, &vp);
7225 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7226 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7227 DisplayModeChanged) {
7229 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7231 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7232 if(swapchain->presentParms.Windowed) {
7233 /* switch from windowed to fs */
7234 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7235 pPresentationParameters->BackBufferWidth,
7236 pPresentationParameters->BackBufferHeight);
7238 /* Fullscreen -> fullscreen mode change */
7239 MoveWindow(swapchain->win_handle, 0, 0,
7240 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7243 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7244 /* Fullscreen -> windowed switch */
7245 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7247 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7248 } else if(!pPresentationParameters->Windowed) {
7249 DWORD style = This->style, exStyle = This->exStyle;
7250 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7251 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7252 * Reset to clear up their mess. Guild Wars also loses the device during that.
7256 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7257 pPresentationParameters->BackBufferWidth,
7258 pPresentationParameters->BackBufferHeight);
7259 This->style = style;
7260 This->exStyle = exStyle;
7263 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7265 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7268 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7269 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7271 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7277 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7278 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7279 /** FIXME: always true at the moment **/
7280 if(!bEnableDialogs) {
7281 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7287 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7289 TRACE("(%p) : pParameters %p\n", This, pParameters);
7291 *pParameters = This->createParms;
7295 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7296 IWineD3DSwapChain *swapchain;
7298 TRACE("Relaying to swapchain\n");
7300 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7301 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, pRamp);
7302 IWineD3DSwapChain_Release(swapchain);
7307 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7308 IWineD3DSwapChain *swapchain;
7310 TRACE("Relaying to swapchain\n");
7312 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7313 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7314 IWineD3DSwapChain_Release(swapchain);
7320 /** ********************************************************
7321 * Notification functions
7322 ** ********************************************************/
7323 /** This function must be called in the release of a resource when ref == 0,
7324 * the contents of resource must still be correct,
7325 * any handles to other resource held by the caller must be closed
7326 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7327 *****************************************************/
7328 static void IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7331 TRACE("(%p) : Adding Resource %p\n", This, resource);
7332 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7335 static void IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7336 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7338 TRACE("(%p) : Removing resource %p\n", This, resource);
7340 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7344 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7346 WINED3DRESOURCETYPE type = IWineD3DResource_GetType(resource);
7349 TRACE("(%p) : resource %p\n", This, resource);
7351 context_resource_released(iface, resource, type);
7354 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7355 case WINED3DRTYPE_SURFACE: {
7358 /* Cleanup any FBO attachments if d3d is enabled */
7359 if(This->d3d_initialized) {
7360 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7361 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7363 TRACE("Last active render target destroyed\n");
7364 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7365 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7366 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7367 * and the lastActiveRenderTarget member shouldn't matter
7370 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7371 TRACE("Activating primary back buffer\n");
7372 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7373 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7374 /* Single buffering environment */
7375 TRACE("Activating primary front buffer\n");
7376 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7378 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7379 /* Implicit render target destroyed, that means the device is being destroyed
7380 * whatever we set here, it shouldn't matter
7382 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7385 /* May happen during ddraw uninitialization */
7386 TRACE("Render target set, but swapchain does not exist!\n");
7387 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7391 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7392 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7393 This->render_targets[i] = NULL;
7396 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7397 This->stencilBufferTarget = NULL;
7403 case WINED3DRTYPE_TEXTURE:
7404 case WINED3DRTYPE_CUBETEXTURE:
7405 case WINED3DRTYPE_VOLUMETEXTURE:
7406 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7407 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7408 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7409 This->stateBlock->textures[counter] = NULL;
7411 if (This->updateStateBlock != This->stateBlock ){
7412 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7413 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7414 This->updateStateBlock->textures[counter] = NULL;
7419 case WINED3DRTYPE_VOLUME:
7420 /* TODO: nothing really? */
7422 case WINED3DRTYPE_VERTEXBUFFER:
7423 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7426 TRACE("Cleaning up stream pointers\n");
7428 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7429 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7430 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7432 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7433 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7434 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7435 This->updateStateBlock->streamSource[streamNumber] = 0;
7436 /* Set changed flag? */
7439 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) */
7440 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7441 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7442 This->stateBlock->streamSource[streamNumber] = 0;
7448 case WINED3DRTYPE_INDEXBUFFER:
7449 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7450 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7451 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7452 This->updateStateBlock->pIndexData = NULL;
7455 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7456 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7457 This->stateBlock->pIndexData = NULL;
7463 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7468 /* Remove the resource from the resourceStore */
7469 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7471 TRACE("Resource released\n");
7475 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7477 IWineD3DResourceImpl *resource, *cursor;
7479 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7481 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7482 TRACE("enumerating resource %p\n", resource);
7483 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7484 ret = pCallback((IWineD3DResource *) resource, pData);
7485 if(ret == S_FALSE) {
7486 TRACE("Canceling enumeration\n");
7493 /**********************************************************
7494 * IWineD3DDevice VTbl follows
7495 **********************************************************/
7497 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7499 /*** IUnknown methods ***/
7500 IWineD3DDeviceImpl_QueryInterface,
7501 IWineD3DDeviceImpl_AddRef,
7502 IWineD3DDeviceImpl_Release,
7503 /*** IWineD3DDevice methods ***/
7504 IWineD3DDeviceImpl_GetParent,
7505 /*** Creation methods**/
7506 IWineD3DDeviceImpl_CreateVertexBuffer,
7507 IWineD3DDeviceImpl_CreateIndexBuffer,
7508 IWineD3DDeviceImpl_CreateStateBlock,
7509 IWineD3DDeviceImpl_CreateSurface,
7510 IWineD3DDeviceImpl_CreateTexture,
7511 IWineD3DDeviceImpl_CreateVolumeTexture,
7512 IWineD3DDeviceImpl_CreateVolume,
7513 IWineD3DDeviceImpl_CreateCubeTexture,
7514 IWineD3DDeviceImpl_CreateQuery,
7515 IWineD3DDeviceImpl_CreateSwapChain,
7516 IWineD3DDeviceImpl_CreateVertexDeclaration,
7517 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7518 IWineD3DDeviceImpl_CreateVertexShader,
7519 IWineD3DDeviceImpl_CreatePixelShader,
7520 IWineD3DDeviceImpl_CreatePalette,
7521 /*** Odd functions **/
7522 IWineD3DDeviceImpl_Init3D,
7523 IWineD3DDeviceImpl_InitGDI,
7524 IWineD3DDeviceImpl_Uninit3D,
7525 IWineD3DDeviceImpl_UninitGDI,
7526 IWineD3DDeviceImpl_SetMultithreaded,
7527 IWineD3DDeviceImpl_EvictManagedResources,
7528 IWineD3DDeviceImpl_GetAvailableTextureMem,
7529 IWineD3DDeviceImpl_GetBackBuffer,
7530 IWineD3DDeviceImpl_GetCreationParameters,
7531 IWineD3DDeviceImpl_GetDeviceCaps,
7532 IWineD3DDeviceImpl_GetDirect3D,
7533 IWineD3DDeviceImpl_GetDisplayMode,
7534 IWineD3DDeviceImpl_SetDisplayMode,
7535 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7536 IWineD3DDeviceImpl_GetRasterStatus,
7537 IWineD3DDeviceImpl_GetSwapChain,
7538 IWineD3DDeviceImpl_Reset,
7539 IWineD3DDeviceImpl_SetDialogBoxMode,
7540 IWineD3DDeviceImpl_SetCursorProperties,
7541 IWineD3DDeviceImpl_SetCursorPosition,
7542 IWineD3DDeviceImpl_ShowCursor,
7543 IWineD3DDeviceImpl_TestCooperativeLevel,
7544 /*** Getters and setters **/
7545 IWineD3DDeviceImpl_SetClipPlane,
7546 IWineD3DDeviceImpl_GetClipPlane,
7547 IWineD3DDeviceImpl_SetClipStatus,
7548 IWineD3DDeviceImpl_GetClipStatus,
7549 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7550 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7551 IWineD3DDeviceImpl_SetDepthStencilSurface,
7552 IWineD3DDeviceImpl_GetDepthStencilSurface,
7553 IWineD3DDeviceImpl_SetFVF,
7554 IWineD3DDeviceImpl_GetFVF,
7555 IWineD3DDeviceImpl_SetGammaRamp,
7556 IWineD3DDeviceImpl_GetGammaRamp,
7557 IWineD3DDeviceImpl_SetIndices,
7558 IWineD3DDeviceImpl_GetIndices,
7559 IWineD3DDeviceImpl_SetBaseVertexIndex,
7560 IWineD3DDeviceImpl_GetBaseVertexIndex,
7561 IWineD3DDeviceImpl_SetLight,
7562 IWineD3DDeviceImpl_GetLight,
7563 IWineD3DDeviceImpl_SetLightEnable,
7564 IWineD3DDeviceImpl_GetLightEnable,
7565 IWineD3DDeviceImpl_SetMaterial,
7566 IWineD3DDeviceImpl_GetMaterial,
7567 IWineD3DDeviceImpl_SetNPatchMode,
7568 IWineD3DDeviceImpl_GetNPatchMode,
7569 IWineD3DDeviceImpl_SetPaletteEntries,
7570 IWineD3DDeviceImpl_GetPaletteEntries,
7571 IWineD3DDeviceImpl_SetPixelShader,
7572 IWineD3DDeviceImpl_GetPixelShader,
7573 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7574 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7575 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7576 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7577 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7578 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7579 IWineD3DDeviceImpl_SetRenderState,
7580 IWineD3DDeviceImpl_GetRenderState,
7581 IWineD3DDeviceImpl_SetRenderTarget,
7582 IWineD3DDeviceImpl_GetRenderTarget,
7583 IWineD3DDeviceImpl_SetFrontBackBuffers,
7584 IWineD3DDeviceImpl_SetSamplerState,
7585 IWineD3DDeviceImpl_GetSamplerState,
7586 IWineD3DDeviceImpl_SetScissorRect,
7587 IWineD3DDeviceImpl_GetScissorRect,
7588 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7589 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7590 IWineD3DDeviceImpl_SetStreamSource,
7591 IWineD3DDeviceImpl_GetStreamSource,
7592 IWineD3DDeviceImpl_SetStreamSourceFreq,
7593 IWineD3DDeviceImpl_GetStreamSourceFreq,
7594 IWineD3DDeviceImpl_SetTexture,
7595 IWineD3DDeviceImpl_GetTexture,
7596 IWineD3DDeviceImpl_SetTextureStageState,
7597 IWineD3DDeviceImpl_GetTextureStageState,
7598 IWineD3DDeviceImpl_SetTransform,
7599 IWineD3DDeviceImpl_GetTransform,
7600 IWineD3DDeviceImpl_SetVertexDeclaration,
7601 IWineD3DDeviceImpl_GetVertexDeclaration,
7602 IWineD3DDeviceImpl_SetVertexShader,
7603 IWineD3DDeviceImpl_GetVertexShader,
7604 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7605 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7606 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7607 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7608 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7609 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7610 IWineD3DDeviceImpl_SetViewport,
7611 IWineD3DDeviceImpl_GetViewport,
7612 IWineD3DDeviceImpl_MultiplyTransform,
7613 IWineD3DDeviceImpl_ValidateDevice,
7614 IWineD3DDeviceImpl_ProcessVertices,
7615 /*** State block ***/
7616 IWineD3DDeviceImpl_BeginStateBlock,
7617 IWineD3DDeviceImpl_EndStateBlock,
7618 /*** Scene management ***/
7619 IWineD3DDeviceImpl_BeginScene,
7620 IWineD3DDeviceImpl_EndScene,
7621 IWineD3DDeviceImpl_Present,
7622 IWineD3DDeviceImpl_Clear,
7624 IWineD3DDeviceImpl_DrawPrimitive,
7625 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7626 IWineD3DDeviceImpl_DrawPrimitiveUP,
7627 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7628 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7629 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7630 IWineD3DDeviceImpl_DrawRectPatch,
7631 IWineD3DDeviceImpl_DrawTriPatch,
7632 IWineD3DDeviceImpl_DeletePatch,
7633 IWineD3DDeviceImpl_ColorFill,
7634 IWineD3DDeviceImpl_UpdateTexture,
7635 IWineD3DDeviceImpl_UpdateSurface,
7636 IWineD3DDeviceImpl_GetFrontBufferData,
7637 /*** object tracking ***/
7638 IWineD3DDeviceImpl_ResourceReleased,
7639 IWineD3DDeviceImpl_EnumResources
7642 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7644 /*** IUnknown methods ***/
7645 IWineD3DDeviceImpl_QueryInterface,
7646 IWineD3DDeviceImpl_AddRef,
7647 IWineD3DDeviceImpl_Release,
7648 /*** IWineD3DDevice methods ***/
7649 IWineD3DDeviceImpl_GetParent,
7650 /*** Creation methods**/
7651 IWineD3DDeviceImpl_CreateVertexBuffer,
7652 IWineD3DDeviceImpl_CreateIndexBuffer,
7653 IWineD3DDeviceImpl_CreateStateBlock,
7654 IWineD3DDeviceImpl_CreateSurface,
7655 IWineD3DDeviceImpl_CreateTexture,
7656 IWineD3DDeviceImpl_CreateVolumeTexture,
7657 IWineD3DDeviceImpl_CreateVolume,
7658 IWineD3DDeviceImpl_CreateCubeTexture,
7659 IWineD3DDeviceImpl_CreateQuery,
7660 IWineD3DDeviceImpl_CreateSwapChain,
7661 IWineD3DDeviceImpl_CreateVertexDeclaration,
7662 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7663 IWineD3DDeviceImpl_CreateVertexShader,
7664 IWineD3DDeviceImpl_CreatePixelShader,
7665 IWineD3DDeviceImpl_CreatePalette,
7666 /*** Odd functions **/
7667 IWineD3DDeviceImpl_Init3D,
7668 IWineD3DDeviceImpl_InitGDI,
7669 IWineD3DDeviceImpl_Uninit3D,
7670 IWineD3DDeviceImpl_UninitGDI,
7671 IWineD3DDeviceImpl_SetMultithreaded,
7672 IWineD3DDeviceImpl_EvictManagedResources,
7673 IWineD3DDeviceImpl_GetAvailableTextureMem,
7674 IWineD3DDeviceImpl_GetBackBuffer,
7675 IWineD3DDeviceImpl_GetCreationParameters,
7676 IWineD3DDeviceImpl_GetDeviceCaps,
7677 IWineD3DDeviceImpl_GetDirect3D,
7678 IWineD3DDeviceImpl_GetDisplayMode,
7679 IWineD3DDeviceImpl_SetDisplayMode,
7680 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7681 IWineD3DDeviceImpl_GetRasterStatus,
7682 IWineD3DDeviceImpl_GetSwapChain,
7683 IWineD3DDeviceImpl_Reset,
7684 IWineD3DDeviceImpl_SetDialogBoxMode,
7685 IWineD3DDeviceImpl_SetCursorProperties,
7686 IWineD3DDeviceImpl_SetCursorPosition,
7687 IWineD3DDeviceImpl_ShowCursor,
7688 IWineD3DDeviceImpl_TestCooperativeLevel,
7689 /*** Getters and setters **/
7690 IWineD3DDeviceImpl_SetClipPlane,
7691 IWineD3DDeviceImpl_GetClipPlane,
7692 IWineD3DDeviceImpl_SetClipStatus,
7693 IWineD3DDeviceImpl_GetClipStatus,
7694 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7695 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7696 IWineD3DDeviceImpl_SetDepthStencilSurface,
7697 IWineD3DDeviceImpl_GetDepthStencilSurface,
7698 IWineD3DDeviceImpl_SetFVF,
7699 IWineD3DDeviceImpl_GetFVF,
7700 IWineD3DDeviceImpl_SetGammaRamp,
7701 IWineD3DDeviceImpl_GetGammaRamp,
7702 IWineD3DDeviceImpl_SetIndices,
7703 IWineD3DDeviceImpl_GetIndices,
7704 IWineD3DDeviceImpl_SetBaseVertexIndex,
7705 IWineD3DDeviceImpl_GetBaseVertexIndex,
7706 IWineD3DDeviceImpl_SetLight,
7707 IWineD3DDeviceImpl_GetLight,
7708 IWineD3DDeviceImpl_SetLightEnable,
7709 IWineD3DDeviceImpl_GetLightEnable,
7710 IWineD3DDeviceImpl_SetMaterial,
7711 IWineD3DDeviceImpl_GetMaterial,
7712 IWineD3DDeviceImpl_SetNPatchMode,
7713 IWineD3DDeviceImpl_GetNPatchMode,
7714 IWineD3DDeviceImpl_SetPaletteEntries,
7715 IWineD3DDeviceImpl_GetPaletteEntries,
7716 IWineD3DDeviceImpl_SetPixelShader,
7717 IWineD3DDeviceImpl_GetPixelShader,
7718 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7719 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7720 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7721 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7722 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7723 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7724 IWineD3DDeviceImpl_SetRenderState,
7725 IWineD3DDeviceImpl_GetRenderState,
7726 IWineD3DDeviceImpl_SetRenderTarget,
7727 IWineD3DDeviceImpl_GetRenderTarget,
7728 IWineD3DDeviceImpl_SetFrontBackBuffers,
7729 IWineD3DDeviceImpl_SetSamplerState,
7730 IWineD3DDeviceImpl_GetSamplerState,
7731 IWineD3DDeviceImpl_SetScissorRect,
7732 IWineD3DDeviceImpl_GetScissorRect,
7733 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7734 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7735 IWineD3DDeviceImpl_SetStreamSource,
7736 IWineD3DDeviceImpl_GetStreamSource,
7737 IWineD3DDeviceImpl_SetStreamSourceFreq,
7738 IWineD3DDeviceImpl_GetStreamSourceFreq,
7739 IWineD3DDeviceImpl_SetTexture,
7740 IWineD3DDeviceImpl_GetTexture,
7741 IWineD3DDeviceImpl_SetTextureStageState,
7742 IWineD3DDeviceImpl_GetTextureStageState,
7743 IWineD3DDeviceImpl_SetTransform,
7744 IWineD3DDeviceImpl_GetTransform,
7745 IWineD3DDeviceImpl_SetVertexDeclaration,
7746 IWineD3DDeviceImpl_GetVertexDeclaration,
7747 IWineD3DDeviceImpl_SetVertexShader,
7748 IWineD3DDeviceImpl_GetVertexShader,
7749 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7750 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7751 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7752 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7753 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7754 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7755 IWineD3DDeviceImpl_SetViewport,
7756 IWineD3DDeviceImpl_GetViewport,
7757 IWineD3DDeviceImpl_MultiplyTransform,
7758 IWineD3DDeviceImpl_ValidateDevice,
7759 IWineD3DDeviceImpl_ProcessVertices,
7760 /*** State block ***/
7761 IWineD3DDeviceImpl_BeginStateBlock,
7762 IWineD3DDeviceImpl_EndStateBlock,
7763 /*** Scene management ***/
7764 IWineD3DDeviceImpl_BeginScene,
7765 IWineD3DDeviceImpl_EndScene,
7766 IWineD3DDeviceImpl_Present,
7767 IWineD3DDeviceImpl_Clear,
7769 IWineD3DDeviceImpl_DrawPrimitive,
7770 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7771 IWineD3DDeviceImpl_DrawPrimitiveUP,
7772 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7773 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7774 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7775 IWineD3DDeviceImpl_DrawRectPatch,
7776 IWineD3DDeviceImpl_DrawTriPatch,
7777 IWineD3DDeviceImpl_DeletePatch,
7778 IWineD3DDeviceImpl_ColorFill,
7779 IWineD3DDeviceImpl_UpdateTexture,
7780 IWineD3DDeviceImpl_UpdateSurface,
7781 IWineD3DDeviceImpl_GetFrontBufferData,
7782 /*** object tracking ***/
7783 IWineD3DDeviceImpl_ResourceReleased,
7784 IWineD3DDeviceImpl_EnumResources
7787 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7788 WINED3DRS_ALPHABLENDENABLE ,
7789 WINED3DRS_ALPHAFUNC ,
7790 WINED3DRS_ALPHAREF ,
7791 WINED3DRS_ALPHATESTENABLE ,
7793 WINED3DRS_COLORWRITEENABLE ,
7794 WINED3DRS_DESTBLEND ,
7795 WINED3DRS_DITHERENABLE ,
7796 WINED3DRS_FILLMODE ,
7797 WINED3DRS_FOGDENSITY ,
7799 WINED3DRS_FOGSTART ,
7800 WINED3DRS_LASTPIXEL ,
7801 WINED3DRS_SHADEMODE ,
7802 WINED3DRS_SRCBLEND ,
7803 WINED3DRS_STENCILENABLE ,
7804 WINED3DRS_STENCILFAIL ,
7805 WINED3DRS_STENCILFUNC ,
7806 WINED3DRS_STENCILMASK ,
7807 WINED3DRS_STENCILPASS ,
7808 WINED3DRS_STENCILREF ,
7809 WINED3DRS_STENCILWRITEMASK ,
7810 WINED3DRS_STENCILZFAIL ,
7811 WINED3DRS_TEXTUREFACTOR ,
7822 WINED3DRS_ZWRITEENABLE
7825 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7826 WINED3DTSS_ADDRESSW ,
7827 WINED3DTSS_ALPHAARG0 ,
7828 WINED3DTSS_ALPHAARG1 ,
7829 WINED3DTSS_ALPHAARG2 ,
7830 WINED3DTSS_ALPHAOP ,
7831 WINED3DTSS_BUMPENVLOFFSET ,
7832 WINED3DTSS_BUMPENVLSCALE ,
7833 WINED3DTSS_BUMPENVMAT00 ,
7834 WINED3DTSS_BUMPENVMAT01 ,
7835 WINED3DTSS_BUMPENVMAT10 ,
7836 WINED3DTSS_BUMPENVMAT11 ,
7837 WINED3DTSS_COLORARG0 ,
7838 WINED3DTSS_COLORARG1 ,
7839 WINED3DTSS_COLORARG2 ,
7840 WINED3DTSS_COLOROP ,
7841 WINED3DTSS_RESULTARG ,
7842 WINED3DTSS_TEXCOORDINDEX ,
7843 WINED3DTSS_TEXTURETRANSFORMFLAGS
7846 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7847 WINED3DSAMP_ADDRESSU ,
7848 WINED3DSAMP_ADDRESSV ,
7849 WINED3DSAMP_ADDRESSW ,
7850 WINED3DSAMP_BORDERCOLOR ,
7851 WINED3DSAMP_MAGFILTER ,
7852 WINED3DSAMP_MINFILTER ,
7853 WINED3DSAMP_MIPFILTER ,
7854 WINED3DSAMP_MIPMAPLODBIAS ,
7855 WINED3DSAMP_MAXMIPLEVEL ,
7856 WINED3DSAMP_MAXANISOTROPY ,
7857 WINED3DSAMP_SRGBTEXTURE ,
7858 WINED3DSAMP_ELEMENTINDEX
7861 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7863 WINED3DRS_AMBIENTMATERIALSOURCE ,
7864 WINED3DRS_CLIPPING ,
7865 WINED3DRS_CLIPPLANEENABLE ,
7866 WINED3DRS_COLORVERTEX ,
7867 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7868 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7869 WINED3DRS_FOGDENSITY ,
7871 WINED3DRS_FOGSTART ,
7872 WINED3DRS_FOGTABLEMODE ,
7873 WINED3DRS_FOGVERTEXMODE ,
7874 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7875 WINED3DRS_LIGHTING ,
7876 WINED3DRS_LOCALVIEWER ,
7877 WINED3DRS_MULTISAMPLEANTIALIAS ,
7878 WINED3DRS_MULTISAMPLEMASK ,
7879 WINED3DRS_NORMALIZENORMALS ,
7880 WINED3DRS_PATCHEDGESTYLE ,
7881 WINED3DRS_POINTSCALE_A ,
7882 WINED3DRS_POINTSCALE_B ,
7883 WINED3DRS_POINTSCALE_C ,
7884 WINED3DRS_POINTSCALEENABLE ,
7885 WINED3DRS_POINTSIZE ,
7886 WINED3DRS_POINTSIZE_MAX ,
7887 WINED3DRS_POINTSIZE_MIN ,
7888 WINED3DRS_POINTSPRITEENABLE ,
7889 WINED3DRS_RANGEFOGENABLE ,
7890 WINED3DRS_SPECULARMATERIALSOURCE ,
7891 WINED3DRS_TWEENFACTOR ,
7892 WINED3DRS_VERTEXBLEND ,
7893 WINED3DRS_CULLMODE ,
7897 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
7898 WINED3DTSS_TEXCOORDINDEX ,
7899 WINED3DTSS_TEXTURETRANSFORMFLAGS
7902 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
7903 WINED3DSAMP_DMAPOFFSET
7906 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
7907 DWORD rep = This->StateTable[state].representative;
7911 WineD3DContext *context;
7914 for(i = 0; i < This->numContexts; i++) {
7915 context = This->contexts[i];
7916 if(isStateDirty(context, rep)) continue;
7918 context->dirtyArray[context->numDirtyEntries++] = rep;
7921 context->isStateDirty[idx] |= (1 << shift);
7925 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7926 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7927 /* The drawable size of a pbuffer render target is the current pbuffer size
7929 *width = dev->pbufferWidth;
7930 *height = dev->pbufferHeight;
7933 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7934 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
7936 *width = This->pow2Width;
7937 *height = This->pow2Height;
7940 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
7941 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
7942 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
7943 * current context's drawable, which is the size of the back buffer of the swapchain
7944 * the active context belongs to. The back buffer of the swapchain is stored as the
7945 * surface the context belongs to.
7947 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
7948 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;