wined3d: Be more careful when deleting FBOs.
[wine.git] / dlls / wined3d / device.c
blobd12aebdef92a532129f813365d8084fdac5f3157
1 /*
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
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
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 */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
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; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
183 This = NULL;
185 return refCount;
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
195 return WINED3D_OK;
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
200 IUnknown *parent) {
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
205 BOOL conv;
207 if(Size == 0) {
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 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);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
225 object->fvf = FVF;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
238 * dx7 apps.
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
251 } else {
252 object->Flags |= VBFLAG_CREATEVBO;
254 return WINED3D_OK;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 ENTER_GL();
270 while(glGetError());
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
276 goto out;
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
283 goto out;
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
294 goto out;
296 LEAVE_GL();
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
298 return;
300 out:
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
303 LEAVE_GL();
304 object->vbo = 0;
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
325 return WINED3D_OK;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
332 int i, j;
333 HRESULT temp_result;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
347 return WINED3D_OK;
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
352 return temp_result;
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
357 else
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
362 object->ref = 1;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
374 struct list *e;
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 struct list *e;
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
566 } else {
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
571 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 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.
583 ******************************** */
585 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) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const GlPixelFormatDesc *glDesc;
590 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
591 TRACE("(%p) Create surface\n",This);
593 /** FIXME: Check ranges on the inputs are valid
594 * MSDN
595 * MultisampleQuality
596 * [in] Quality level. The valid range is between zero and one less than the level
597 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
598 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
599 * values of paired render targets, depth stencil surfaces, and the MultiSample type
600 * must all match.
601 *******************************/
605 * TODO: Discard MSDN
606 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
608 * If this flag is set, the contents of the depth stencil buffer will be
609 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
610 * with a different depth surface.
612 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
613 ***************************/
615 if(MultisampleQuality > 0) {
616 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
617 MultisampleQuality=0;
620 /** FIXME: Check that the format is supported
621 * by the device.
622 *******************************/
624 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
625 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
626 * space!
627 *********************************/
628 if (WINED3DFMT_UNKNOWN == Format) {
629 Size = 0;
630 } else if (Format == WINED3DFMT_DXT1) {
631 /* DXT1 is half byte per pixel */
632 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
634 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
635 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
636 Format == WINED3DFMT_ATI2N) {
637 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
638 } else {
639 /* The pitch is a multiple of 4 bytes */
640 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
641 Size *= Height;
644 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
646 /** Create and initialise the surface resource **/
647 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
648 /* "Standalone" surface */
649 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
651 object->currentDesc.Width = Width;
652 object->currentDesc.Height = Height;
653 object->currentDesc.MultiSampleType = MultiSample;
654 object->currentDesc.MultiSampleQuality = MultisampleQuality;
655 object->glDescription.level = Level;
656 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
657 list_init(&object->overlays);
659 /* Flags */
660 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
661 object->Flags |= Discard ? SFLAG_DISCARD : 0;
662 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
663 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
666 if (WINED3DFMT_UNKNOWN != Format) {
667 object->bytesPerPixel = tableEntry->bpp;
668 } else {
669 object->bytesPerPixel = 0;
672 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
674 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
676 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
677 * this function is too deep to need to care about things like this.
678 * Levels need to be checked too, and possibly Type since they all affect what can be done.
679 * ****************************************/
680 switch(Pool) {
681 case WINED3DPOOL_SCRATCH:
682 if(!Lockable)
683 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
684 "which are mutually exclusive, setting lockable to TRUE\n");
685 Lockable = TRUE;
686 break;
687 case WINED3DPOOL_SYSTEMMEM:
688 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
689 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
690 case WINED3DPOOL_MANAGED:
691 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
692 "Usage of DYNAMIC which are mutually exclusive, not doing "
693 "anything just telling you.\n");
694 break;
695 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
696 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
697 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
698 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
699 break;
700 default:
701 FIXME("(%p) Unknown pool %d\n", This, Pool);
702 break;
705 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
706 FIXME("Trying to create a render target that isn't in the default pool\n");
709 /* mark the texture as dirty so that it gets loaded first time around*/
710 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
711 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
712 This, Width, Height, Format, debug_d3dformat(Format),
713 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
715 /* Look at the implementation and set the correct Vtable */
716 switch(Impl) {
717 case SURFACE_OPENGL:
718 /* Check if a 3D adapter is available when creating gl surfaces */
719 if(!This->adapter) {
720 ERR("OpenGL surfaces are not available without opengl\n");
721 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
722 HeapFree(GetProcessHeap(), 0, object);
723 return WINED3DERR_NOTAVAILABLE;
725 break;
727 case SURFACE_GDI:
728 object->lpVtbl = &IWineGDISurface_Vtbl;
729 break;
731 default:
732 /* To be sure to catch this */
733 ERR("Unknown requested surface implementation %d!\n", Impl);
734 IWineD3DSurface_Release((IWineD3DSurface *) object);
735 return WINED3DERR_INVALIDCALL;
738 list_init(&object->renderbuffers);
740 /* Call the private setup routine */
741 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
745 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
746 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
747 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
748 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
751 IWineD3DTextureImpl *object;
752 unsigned int i;
753 UINT tmpW;
754 UINT tmpH;
755 HRESULT hr;
756 unsigned int pow2Width;
757 unsigned int pow2Height;
758 const GlPixelFormatDesc *glDesc;
759 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
761 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
762 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
763 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
765 /* TODO: It should only be possible to create textures for formats
766 that are reported as supported */
767 if (WINED3DFMT_UNKNOWN >= Format) {
768 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
769 return WINED3DERR_INVALIDCALL;
772 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
773 D3DINITIALIZEBASETEXTURE(object->baseTexture);
774 object->width = Width;
775 object->height = Height;
777 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
778 object->baseTexture.minMipLookup = &minMipLookup;
779 object->baseTexture.magLookup = &magLookup;
780 } else {
781 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
782 object->baseTexture.magLookup = &magLookup_noFilter;
785 /** Non-power2 support **/
786 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
787 pow2Width = Width;
788 pow2Height = Height;
789 } else {
790 /* Find the nearest pow2 match */
791 pow2Width = pow2Height = 1;
792 while (pow2Width < Width) pow2Width <<= 1;
793 while (pow2Height < Height) pow2Height <<= 1;
795 if(pow2Width != Width || pow2Height != Height) {
796 if(Levels > 1) {
797 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
798 HeapFree(GetProcessHeap(), 0, object);
799 *ppTexture = NULL;
800 return WINED3DERR_INVALIDCALL;
801 } else {
802 Levels = 1;
807 /** FIXME: add support for real non-power-two if it's provided by the video card **/
808 /* Precalculated scaling for 'faked' non power of two texture coords.
809 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
810 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
811 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
813 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
814 object->baseTexture.pow2Matrix[0] = 1.0;
815 object->baseTexture.pow2Matrix[5] = 1.0;
816 object->baseTexture.pow2Matrix[10] = 1.0;
817 object->baseTexture.pow2Matrix[15] = 1.0;
818 object->target = GL_TEXTURE_2D;
819 object->cond_np2 = TRUE;
820 pow2Width = Width;
821 pow2Height = Height;
822 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
823 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
824 (Width != pow2Width || Height != pow2Height) &&
825 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
827 object->baseTexture.pow2Matrix[0] = (float)Width;
828 object->baseTexture.pow2Matrix[5] = (float)Height;
829 object->baseTexture.pow2Matrix[10] = 1.0;
830 object->baseTexture.pow2Matrix[15] = 1.0;
831 object->target = GL_TEXTURE_RECTANGLE_ARB;
832 object->cond_np2 = TRUE;
833 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
834 } else {
835 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
836 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
837 object->baseTexture.pow2Matrix[10] = 1.0;
838 object->baseTexture.pow2Matrix[15] = 1.0;
839 object->target = GL_TEXTURE_2D;
840 object->cond_np2 = FALSE;
842 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
844 /* Calculate levels for mip mapping */
845 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
846 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
847 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
848 return WINED3DERR_INVALIDCALL;
850 if(Levels > 1) {
851 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
852 return WINED3DERR_INVALIDCALL;
854 object->baseTexture.levels = 1;
855 } else if (Levels == 0) {
856 TRACE("calculating levels %d\n", object->baseTexture.levels);
857 object->baseTexture.levels++;
858 tmpW = Width;
859 tmpH = Height;
860 while (tmpW > 1 || tmpH > 1) {
861 tmpW = max(1, tmpW >> 1);
862 tmpH = max(1, tmpH >> 1);
863 object->baseTexture.levels++;
865 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
868 /* Generate all the surfaces */
869 tmpW = Width;
870 tmpH = Height;
871 for (i = 0; i < object->baseTexture.levels; i++)
873 /* use the callback to create the texture surface */
874 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
875 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
876 FIXME("Failed to create surface %p\n", object);
877 /* clean up */
878 object->surfaces[i] = NULL;
879 IWineD3DTexture_Release((IWineD3DTexture *)object);
881 *ppTexture = NULL;
882 return hr;
885 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
886 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
887 /* calculate the next mipmap level */
888 tmpW = max(1, tmpW >> 1);
889 tmpH = max(1, tmpH >> 1);
891 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
893 TRACE("(%p) : Created texture %p\n", This, object);
894 return WINED3D_OK;
897 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
898 UINT Width, UINT Height, UINT Depth,
899 UINT Levels, DWORD Usage,
900 WINED3DFORMAT Format, WINED3DPOOL Pool,
901 IWineD3DVolumeTexture **ppVolumeTexture,
902 HANDLE *pSharedHandle, IUnknown *parent,
903 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
905 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
906 IWineD3DVolumeTextureImpl *object;
907 unsigned int i;
908 UINT tmpW;
909 UINT tmpH;
910 UINT tmpD;
911 const GlPixelFormatDesc *glDesc;
913 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
915 /* TODO: It should only be possible to create textures for formats
916 that are reported as supported */
917 if (WINED3DFMT_UNKNOWN >= Format) {
918 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
919 return WINED3DERR_INVALIDCALL;
921 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
922 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
923 return WINED3DERR_INVALIDCALL;
926 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
927 D3DINITIALIZEBASETEXTURE(object->baseTexture);
929 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
930 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
932 object->width = Width;
933 object->height = Height;
934 object->depth = Depth;
936 /* Is NP2 support for volumes needed? */
937 object->baseTexture.pow2Matrix[ 0] = 1.0;
938 object->baseTexture.pow2Matrix[ 5] = 1.0;
939 object->baseTexture.pow2Matrix[10] = 1.0;
940 object->baseTexture.pow2Matrix[15] = 1.0;
942 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
943 object->baseTexture.minMipLookup = &minMipLookup;
944 object->baseTexture.magLookup = &magLookup;
945 } else {
946 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
947 object->baseTexture.magLookup = &magLookup_noFilter;
950 /* Calculate levels for mip mapping */
951 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
952 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
953 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
954 return WINED3DERR_INVALIDCALL;
956 if(Levels > 1) {
957 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
958 return WINED3DERR_INVALIDCALL;
960 Levels = 1;
961 } else if (Levels == 0) {
962 object->baseTexture.levels++;
963 tmpW = Width;
964 tmpH = Height;
965 tmpD = Depth;
966 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
967 tmpW = max(1, tmpW >> 1);
968 tmpH = max(1, tmpH >> 1);
969 tmpD = max(1, tmpD >> 1);
970 object->baseTexture.levels++;
972 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
975 /* Generate all the surfaces */
976 tmpW = Width;
977 tmpH = Height;
978 tmpD = Depth;
980 for (i = 0; i < object->baseTexture.levels; i++)
982 HRESULT hr;
983 /* Create the volume */
984 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
985 &object->volumes[i], pSharedHandle);
987 if(FAILED(hr)) {
988 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
989 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
990 *ppVolumeTexture = NULL;
991 return hr;
994 /* Set its container to this object */
995 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
997 /* calculate the next mipmap level */
998 tmpW = max(1, tmpW >> 1);
999 tmpH = max(1, tmpH >> 1);
1000 tmpD = max(1, tmpD >> 1);
1002 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1004 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1005 TRACE("(%p) : Created volume texture %p\n", This, object);
1006 return WINED3D_OK;
1009 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1010 UINT Width, UINT Height, UINT Depth,
1011 DWORD Usage,
1012 WINED3DFORMAT Format, WINED3DPOOL Pool,
1013 IWineD3DVolume** ppVolume,
1014 HANDLE* pSharedHandle, IUnknown *parent) {
1016 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1017 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1018 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1020 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1021 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1022 return WINED3DERR_INVALIDCALL;
1025 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1027 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1028 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1030 object->currentDesc.Width = Width;
1031 object->currentDesc.Height = Height;
1032 object->currentDesc.Depth = Depth;
1033 object->bytesPerPixel = formatDesc->bpp;
1035 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1036 object->lockable = TRUE;
1037 object->locked = FALSE;
1038 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1039 object->dirty = TRUE;
1041 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1044 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1045 UINT Levels, DWORD Usage,
1046 WINED3DFORMAT Format, WINED3DPOOL Pool,
1047 IWineD3DCubeTexture **ppCubeTexture,
1048 HANDLE *pSharedHandle, IUnknown *parent,
1049 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1052 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1053 unsigned int i, j;
1054 UINT tmpW;
1055 HRESULT hr;
1056 unsigned int pow2EdgeLength = EdgeLength;
1057 const GlPixelFormatDesc *glDesc;
1058 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1060 /* TODO: It should only be possible to create textures for formats
1061 that are reported as supported */
1062 if (WINED3DFMT_UNKNOWN >= Format) {
1063 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1064 return WINED3DERR_INVALIDCALL;
1067 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1068 WARN("(%p) : Tried to create not supported cube texture\n", This);
1069 return WINED3DERR_INVALIDCALL;
1072 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1073 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1075 TRACE("(%p) Create Cube Texture\n", This);
1077 /** Non-power2 support **/
1079 /* Find the nearest pow2 match */
1080 pow2EdgeLength = 1;
1081 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1083 object->edgeLength = EdgeLength;
1084 /* TODO: support for native non-power 2 */
1085 /* Precalculated scaling for 'faked' non power of two texture coords */
1086 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1087 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1088 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1089 object->baseTexture.pow2Matrix[15] = 1.0;
1091 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1092 object->baseTexture.minMipLookup = &minMipLookup;
1093 object->baseTexture.magLookup = &magLookup;
1094 } else {
1095 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1096 object->baseTexture.magLookup = &magLookup_noFilter;
1099 /* Calculate levels for mip mapping */
1100 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1101 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1102 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1103 HeapFree(GetProcessHeap(), 0, object);
1104 *ppCubeTexture = NULL;
1106 return WINED3DERR_INVALIDCALL;
1108 if(Levels > 1) {
1109 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1110 HeapFree(GetProcessHeap(), 0, object);
1111 *ppCubeTexture = NULL;
1113 return WINED3DERR_INVALIDCALL;
1115 Levels = 1;
1116 } else if (Levels == 0) {
1117 object->baseTexture.levels++;
1118 tmpW = EdgeLength;
1119 while (tmpW > 1) {
1120 tmpW = max(1, tmpW >> 1);
1121 object->baseTexture.levels++;
1123 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1126 /* Generate all the surfaces */
1127 tmpW = EdgeLength;
1128 for (i = 0; i < object->baseTexture.levels; i++) {
1130 /* Create the 6 faces */
1131 for (j = 0; j < 6; j++) {
1133 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1134 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1136 if(hr!= WINED3D_OK) {
1137 /* clean up */
1138 int k;
1139 int l;
1140 for (l = 0; l < j; l++) {
1141 IWineD3DSurface_Release(object->surfaces[l][i]);
1143 for (k = 0; k < i; k++) {
1144 for (l = 0; l < 6; l++) {
1145 IWineD3DSurface_Release(object->surfaces[l][k]);
1149 FIXME("(%p) Failed to create surface\n",object);
1150 HeapFree(GetProcessHeap(),0,object);
1151 *ppCubeTexture = NULL;
1152 return hr;
1154 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1155 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1157 tmpW = max(1, tmpW >> 1);
1159 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1161 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1162 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1163 return WINED3D_OK;
1166 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1167 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1168 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1169 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1170 const IWineD3DQueryVtbl *vtable;
1172 /* Just a check to see if we support this type of query */
1173 switch(Type) {
1174 case WINED3DQUERYTYPE_OCCLUSION:
1175 TRACE("(%p) occlusion query\n", This);
1176 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1177 hr = WINED3D_OK;
1178 else
1179 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1181 vtable = &IWineD3DOcclusionQuery_Vtbl;
1182 break;
1184 case WINED3DQUERYTYPE_EVENT:
1185 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1186 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1187 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1189 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1191 vtable = &IWineD3DEventQuery_Vtbl;
1192 hr = WINED3D_OK;
1193 break;
1195 case WINED3DQUERYTYPE_VCACHE:
1196 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1197 case WINED3DQUERYTYPE_VERTEXSTATS:
1198 case WINED3DQUERYTYPE_TIMESTAMP:
1199 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1200 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1201 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1202 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1203 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1204 case WINED3DQUERYTYPE_PIXELTIMINGS:
1205 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1206 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1207 default:
1208 /* Use the base Query vtable until we have a special one for each query */
1209 vtable = &IWineD3DQuery_Vtbl;
1210 FIXME("(%p) Unhandled query type %d\n", This, Type);
1212 if(NULL == ppQuery || hr != WINED3D_OK) {
1213 return hr;
1216 D3DCREATEOBJECTINSTANCE(object, Query)
1217 object->lpVtbl = vtable;
1218 object->type = Type;
1219 object->state = QUERY_CREATED;
1220 /* allocated the 'extended' data based on the type of query requested */
1221 switch(Type){
1222 case WINED3DQUERYTYPE_OCCLUSION:
1223 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1224 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1226 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1227 TRACE("(%p) Allocating data for an occlusion query\n", This);
1228 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1229 break;
1231 case WINED3DQUERYTYPE_EVENT:
1232 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1233 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1235 if(GL_SUPPORT(APPLE_FENCE)) {
1236 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1237 checkGLcall("glGenFencesAPPLE");
1238 } else if(GL_SUPPORT(NV_FENCE)) {
1239 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1240 checkGLcall("glGenFencesNV");
1242 break;
1244 case WINED3DQUERYTYPE_VCACHE:
1245 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1246 case WINED3DQUERYTYPE_VERTEXSTATS:
1247 case WINED3DQUERYTYPE_TIMESTAMP:
1248 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1249 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1250 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1251 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1252 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1253 case WINED3DQUERYTYPE_PIXELTIMINGS:
1254 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1255 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1256 default:
1257 object->extendedData = 0;
1258 FIXME("(%p) Unhandled query type %d\n",This , Type);
1260 TRACE("(%p) : Created Query %p\n", This, object);
1261 return WINED3D_OK;
1264 /*****************************************************************************
1265 * IWineD3DDeviceImpl_SetupFullscreenWindow
1267 * Helper function that modifies a HWND's Style and ExStyle for proper
1268 * fullscreen use.
1270 * Params:
1271 * iface: Pointer to the IWineD3DDevice interface
1272 * window: Window to setup
1274 *****************************************************************************/
1275 static LONG fullscreen_style(LONG orig_style) {
1276 LONG style = orig_style;
1277 style &= ~WS_CAPTION;
1278 style &= ~WS_THICKFRAME;
1280 /* Make sure the window is managed, otherwise we won't get keyboard input */
1281 style |= WS_POPUP | WS_SYSMENU;
1283 return style;
1286 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1287 LONG exStyle = orig_exStyle;
1289 /* Filter out window decorations */
1290 exStyle &= ~WS_EX_WINDOWEDGE;
1291 exStyle &= ~WS_EX_CLIENTEDGE;
1293 return exStyle;
1296 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1299 LONG style, exStyle;
1300 /* Don't do anything if an original style is stored.
1301 * That shouldn't happen
1303 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1304 if (This->style || This->exStyle) {
1305 ERR("(%p): Want to change the window parameters of HWND %p, but "
1306 "another style is stored for restoration afterwards\n", This, window);
1309 /* Get the parameters and save them */
1310 style = GetWindowLongW(window, GWL_STYLE);
1311 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1312 This->style = style;
1313 This->exStyle = exStyle;
1315 style = fullscreen_style(style);
1316 exStyle = fullscreen_exStyle(exStyle);
1318 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1319 This->style, This->exStyle, style, exStyle);
1321 SetWindowLongW(window, GWL_STYLE, style);
1322 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1324 /* Inform the window about the update. */
1325 SetWindowPos(window, HWND_TOP, 0, 0,
1326 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1329 /*****************************************************************************
1330 * IWineD3DDeviceImpl_RestoreWindow
1332 * Helper function that restores a windows' properties when taking it out
1333 * of fullscreen mode
1335 * Params:
1336 * iface: Pointer to the IWineD3DDevice interface
1337 * window: Window to setup
1339 *****************************************************************************/
1340 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1342 LONG style, exStyle;
1344 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1345 * switch, do nothing
1347 if (!This->style && !This->exStyle) return;
1349 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1350 This, window, This->style, This->exStyle);
1352 style = GetWindowLongW(window, GWL_STYLE);
1353 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1355 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1356 * Some applications change it before calling Reset() when switching between windowed and
1357 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1359 if(style == fullscreen_style(This->style) &&
1360 exStyle == fullscreen_style(This->exStyle)) {
1361 SetWindowLongW(window, GWL_STYLE, This->style);
1362 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1365 /* Delete the old values */
1366 This->style = 0;
1367 This->exStyle = 0;
1369 /* Inform the window about the update */
1370 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1371 0, 0, 0, 0, /* Pos, Size, ignored */
1372 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1375 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1376 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1377 IUnknown* parent,
1378 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1379 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1380 WINED3DSURFTYPE surface_type) {
1381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1383 HDC hDc;
1384 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1385 HRESULT hr = WINED3D_OK;
1386 IUnknown *bufferParent;
1387 BOOL displaymode_set = FALSE;
1388 WINED3DDISPLAYMODE Mode;
1389 const StaticPixelFormatDesc *formatDesc;
1391 TRACE("(%p) : Created Additional Swap Chain\n", This);
1393 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1394 * does a device hold a reference to a swap chain giving them a lifetime of the device
1395 * or does the swap chain notify the device of its destruction.
1396 *******************************/
1398 /* Check the params */
1399 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1400 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1401 return WINED3DERR_INVALIDCALL;
1402 } else if (pPresentationParameters->BackBufferCount > 1) {
1403 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");
1406 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1407 switch(surface_type) {
1408 case SURFACE_GDI:
1409 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1410 break;
1411 case SURFACE_OPENGL:
1412 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1413 break;
1414 case SURFACE_UNKNOWN:
1415 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1416 return WINED3DERR_INVALIDCALL;
1419 /*********************
1420 * Lookup the window Handle and the relating X window handle
1421 ********************/
1423 /* Setup hwnd we are using, plus which display this equates to */
1424 object->win_handle = pPresentationParameters->hDeviceWindow;
1425 if (!object->win_handle) {
1426 object->win_handle = This->createParms.hFocusWindow;
1428 if(!pPresentationParameters->Windowed && object->win_handle) {
1429 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1430 pPresentationParameters->BackBufferWidth,
1431 pPresentationParameters->BackBufferHeight);
1434 hDc = GetDC(object->win_handle);
1435 TRACE("Using hDc %p\n", hDc);
1437 if (NULL == hDc) {
1438 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1439 return WINED3DERR_NOTAVAILABLE;
1442 /* Get info on the current display setup */
1443 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1444 object->orig_width = Mode.Width;
1445 object->orig_height = Mode.Height;
1446 object->orig_fmt = Mode.Format;
1447 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1449 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1450 * then the corresponding dimension of the client area of the hDeviceWindow
1451 * (or the focus window, if hDeviceWindow is NULL) is taken.
1452 **********************/
1454 if (pPresentationParameters->Windowed &&
1455 ((pPresentationParameters->BackBufferWidth == 0) ||
1456 (pPresentationParameters->BackBufferHeight == 0) ||
1457 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1459 RECT Rect;
1460 GetClientRect(object->win_handle, &Rect);
1462 if (pPresentationParameters->BackBufferWidth == 0) {
1463 pPresentationParameters->BackBufferWidth = Rect.right;
1464 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1466 if (pPresentationParameters->BackBufferHeight == 0) {
1467 pPresentationParameters->BackBufferHeight = Rect.bottom;
1468 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1470 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1471 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1472 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1476 /* Put the correct figures in the presentation parameters */
1477 TRACE("Copying across presentation parameters\n");
1478 object->presentParms = *pPresentationParameters;
1480 TRACE("calling rendertarget CB\n");
1481 hr = D3DCB_CreateRenderTarget(This->parent,
1482 parent,
1483 object->presentParms.BackBufferWidth,
1484 object->presentParms.BackBufferHeight,
1485 object->presentParms.BackBufferFormat,
1486 object->presentParms.MultiSampleType,
1487 object->presentParms.MultiSampleQuality,
1488 TRUE /* Lockable */,
1489 &object->frontBuffer,
1490 NULL /* pShared (always null)*/);
1491 if (object->frontBuffer != NULL) {
1492 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1493 if(surface_type == SURFACE_OPENGL) {
1494 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1496 } else {
1497 ERR("Failed to create the front buffer\n");
1498 goto error;
1501 /*********************
1502 * Windowed / Fullscreen
1503 *******************/
1506 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1507 * so we should really check to see if there is a fullscreen swapchain already
1508 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1509 **************************************/
1511 if (!pPresentationParameters->Windowed) {
1512 WINED3DDISPLAYMODE mode;
1515 /* Change the display settings */
1516 mode.Width = pPresentationParameters->BackBufferWidth;
1517 mode.Height = pPresentationParameters->BackBufferHeight;
1518 mode.Format = pPresentationParameters->BackBufferFormat;
1519 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1521 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1522 displaymode_set = TRUE;
1526 * Create an opengl context for the display visual
1527 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1528 * use different properties after that point in time. FIXME: How to handle when requested format
1529 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1530 * it chooses is identical to the one already being used!
1531 **********************************/
1532 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1534 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1535 if(!object->context)
1536 return E_OUTOFMEMORY;
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;
1544 goto error;
1545 } else {
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) {
1555 int i;
1557 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1558 if(!object->backBuffer) {
1559 ERR("Out of memory\n");
1560 hr = E_OUTOFMEMORY;
1561 goto error;
1564 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1565 TRACE("calling rendertarget CB\n");
1566 hr = D3DCB_CreateRenderTarget(This->parent,
1567 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)*/);
1576 if(hr == WINED3D_OK && object->backBuffer[i]) {
1577 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1578 } else {
1579 ERR("Cannot create new back buffer\n");
1580 goto error;
1582 if(surface_type == SURFACE_OPENGL) {
1583 ENTER_GL();
1584 glDrawBuffer(GL_BACK);
1585 checkGLcall("glDrawBuffer(GL_BACK)");
1586 LEAVE_GL();
1589 } else {
1590 object->backBuffer = NULL;
1592 /* Single buffering - draw to front buffer */
1593 if(surface_type == SURFACE_OPENGL) {
1594 ENTER_GL();
1595 glDrawBuffer(GL_FRONT);
1596 checkGLcall("glDrawBuffer(GL_FRONT)");
1597 LEAVE_GL();
1601 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1602 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && 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,
1606 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 (This->auto_depth_stencil_buffer != NULL)
1616 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1619 /** TODO: A check on width, height and multisample types
1620 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1621 ****************************/
1622 object->wantsDepthStencilBuffer = TRUE;
1623 } else {
1624 object->wantsDepthStencilBuffer = FALSE;
1627 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1629 TRACE("Created swapchain %p\n", object);
1630 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1631 return WINED3D_OK;
1633 error:
1634 if (displaymode_set) {
1635 DEVMODEW devmode;
1636 RECT clip_rc;
1638 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1639 ClipCursor(NULL);
1641 /* Change the display settings */
1642 memset(&devmode, 0, sizeof(devmode));
1643 devmode.dmSize = sizeof(devmode);
1644 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1645 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1646 devmode.dmPelsWidth = object->orig_width;
1647 devmode.dmPelsHeight = object->orig_height;
1648 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1651 if (object->backBuffer) {
1652 int i;
1653 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1654 if(object->backBuffer[i]) {
1655 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1656 IUnknown_Release(bufferParent); /* once for the get parent */
1657 if (IUnknown_Release(bufferParent) > 0) {
1658 FIXME("(%p) Something's still holding the back buffer\n",This);
1662 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1663 object->backBuffer = NULL;
1665 if(object->context[0])
1666 DestroyContext(This, object->context[0]);
1667 if(object->frontBuffer) {
1668 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1669 IUnknown_Release(bufferParent); /* once for the get parent */
1670 if (IUnknown_Release(bufferParent) > 0) {
1671 FIXME("(%p) Something's still holding the front buffer\n",This);
1674 HeapFree(GetProcessHeap(), 0, object);
1675 return hr;
1678 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1679 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1680 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1681 TRACE("(%p)\n", This);
1683 return This->NumberOfSwapChains;
1686 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1690 if(iSwapChain < This->NumberOfSwapChains) {
1691 *pSwapChain = This->swapchains[iSwapChain];
1692 IWineD3DSwapChain_AddRef(*pSwapChain);
1693 TRACE("(%p) returning %p\n", This, *pSwapChain);
1694 return WINED3D_OK;
1695 } else {
1696 TRACE("Swapchain out of range\n");
1697 *pSwapChain = NULL;
1698 return WINED3DERR_INVALIDCALL;
1702 /*****
1703 * Vertex Declaration
1704 *****/
1705 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1706 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1707 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1708 IWineD3DVertexDeclarationImpl *object = NULL;
1709 HRESULT hr = WINED3D_OK;
1711 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1712 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1714 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1716 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1717 if(FAILED(hr)) {
1718 *ppVertexDeclaration = NULL;
1719 HeapFree(GetProcessHeap(), 0, object);
1722 return hr;
1725 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1726 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1728 unsigned int idx, idx2;
1729 unsigned int offset;
1730 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1731 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1732 BOOL has_blend_idx = has_blend &&
1733 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1734 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1735 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1736 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1737 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1738 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1739 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1741 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1742 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1744 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1745 WINED3DVERTEXELEMENT *elements = NULL;
1747 unsigned int size;
1748 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1749 if (has_blend_idx) num_blends--;
1751 /* Compute declaration size */
1752 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1753 has_psize + has_diffuse + has_specular + num_textures + 1;
1755 /* convert the declaration */
1756 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1757 if (!elements)
1758 return 0;
1760 elements[size-1] = end_element;
1761 idx = 0;
1762 if (has_pos) {
1763 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1765 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1767 else {
1768 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1769 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1771 elements[idx].UsageIndex = 0;
1772 idx++;
1774 if (has_blend && (num_blends > 0)) {
1775 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1776 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1777 else
1778 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1779 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1780 elements[idx].UsageIndex = 0;
1781 idx++;
1783 if (has_blend_idx) {
1784 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1785 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1786 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1787 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1788 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1789 else
1790 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1791 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1792 elements[idx].UsageIndex = 0;
1793 idx++;
1795 if (has_normal) {
1796 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1797 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1798 elements[idx].UsageIndex = 0;
1799 idx++;
1801 if (has_psize) {
1802 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1803 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1804 elements[idx].UsageIndex = 0;
1805 idx++;
1807 if (has_diffuse) {
1808 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1809 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1810 elements[idx].UsageIndex = 0;
1811 idx++;
1813 if (has_specular) {
1814 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1815 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1816 elements[idx].UsageIndex = 1;
1817 idx++;
1819 for (idx2 = 0; idx2 < num_textures; idx2++) {
1820 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1821 switch (numcoords) {
1822 case WINED3DFVF_TEXTUREFORMAT1:
1823 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1824 break;
1825 case WINED3DFVF_TEXTUREFORMAT2:
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1827 break;
1828 case WINED3DFVF_TEXTUREFORMAT3:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1830 break;
1831 case WINED3DFVF_TEXTUREFORMAT4:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1833 break;
1835 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1836 elements[idx].UsageIndex = idx2;
1837 idx++;
1840 /* Now compute offsets, and initialize the rest of the fields */
1841 for (idx = 0, offset = 0; idx < size-1; idx++) {
1842 elements[idx].Stream = 0;
1843 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1844 elements[idx].Offset = offset;
1845 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1848 *ppVertexElements = elements;
1849 return size;
1852 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1853 WINED3DVERTEXELEMENT* elements = NULL;
1854 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1855 unsigned int size;
1856 DWORD hr;
1858 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1859 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1861 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1862 HeapFree(GetProcessHeap(), 0, elements);
1863 if (hr != S_OK) return hr;
1865 return WINED3D_OK;
1868 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1869 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1870 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1871 HRESULT hr = WINED3D_OK;
1872 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1873 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1875 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1877 if (vertex_declaration) {
1878 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1881 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1883 if (WINED3D_OK != hr) {
1884 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1885 IWineD3DVertexShader_Release(*ppVertexShader);
1886 return WINED3DERR_INVALIDCALL;
1888 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1890 return WINED3D_OK;
1893 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1894 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1895 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1896 HRESULT hr = WINED3D_OK;
1898 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1899 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1900 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1901 if (WINED3D_OK == hr) {
1902 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1903 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1904 } else {
1905 WARN("(%p) : Failed to create pixel shader\n", This);
1908 return hr;
1911 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1913 IWineD3DPaletteImpl *object;
1914 HRESULT hr;
1915 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1917 /* Create the new object */
1918 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1919 if(!object) {
1920 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1921 return E_OUTOFMEMORY;
1924 object->lpVtbl = &IWineD3DPalette_Vtbl;
1925 object->ref = 1;
1926 object->Flags = Flags;
1927 object->parent = Parent;
1928 object->wineD3DDevice = This;
1929 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1931 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1933 if(!object->hpal) {
1934 HeapFree( GetProcessHeap(), 0, object);
1935 return E_OUTOFMEMORY;
1938 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1939 if(FAILED(hr)) {
1940 IWineD3DPalette_Release((IWineD3DPalette *) object);
1941 return hr;
1944 *Palette = (IWineD3DPalette *) object;
1946 return WINED3D_OK;
1949 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1950 HBITMAP hbm;
1951 BITMAP bm;
1952 HRESULT hr;
1953 HDC dcb = NULL, dcs = NULL;
1954 WINEDDCOLORKEY colorkey;
1956 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1957 if(hbm)
1959 GetObjectA(hbm, sizeof(BITMAP), &bm);
1960 dcb = CreateCompatibleDC(NULL);
1961 if(!dcb) goto out;
1962 SelectObject(dcb, hbm);
1964 else
1966 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1967 * couldn't be loaded
1969 memset(&bm, 0, sizeof(bm));
1970 bm.bmWidth = 32;
1971 bm.bmHeight = 32;
1974 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1975 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1976 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1977 if(FAILED(hr)) {
1978 ERR("Wine logo requested, but failed to create surface\n");
1979 goto out;
1982 if(dcb) {
1983 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1984 if(FAILED(hr)) goto out;
1985 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1986 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1988 colorkey.dwColorSpaceLowValue = 0;
1989 colorkey.dwColorSpaceHighValue = 0;
1990 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1991 } else {
1992 /* Fill the surface with a white color to show that wined3d is there */
1993 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1996 out:
1997 if(dcb) {
1998 DeleteDC(dcb);
2000 if(hbm) {
2001 DeleteObject(hbm);
2003 return;
2006 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2007 unsigned int i;
2008 /* Under DirectX you can have texture stage operations even if no texture is
2009 bound, whereas opengl will only do texture operations when a valid texture is
2010 bound. We emulate this by creating dummy textures and binding them to each
2011 texture stage, but disable all stages by default. Hence if a stage is enabled
2012 then the default texture will kick in until replaced by a SetTexture call */
2013 ENTER_GL();
2015 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2016 /* The dummy texture does not have client storage backing */
2017 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2018 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2020 for (i = 0; i < GL_LIMITS(textures); i++) {
2021 GLubyte white = 255;
2023 /* Make appropriate texture active */
2024 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2025 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2026 checkGLcall("glActiveTextureARB");
2027 } else if (i > 0) {
2028 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2031 /* Generate an opengl texture name */
2032 glGenTextures(1, &This->dummyTextureName[i]);
2033 checkGLcall("glGenTextures");
2034 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2036 /* Generate a dummy 2d texture (not using 1d because they cause many
2037 * DRI drivers fall back to sw) */
2038 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2039 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2040 checkGLcall("glBindTexture");
2042 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2043 checkGLcall("glTexImage2D");
2045 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2046 /* Reenable because if supported it is enabled by default */
2047 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2048 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2051 LEAVE_GL();
2054 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2055 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2056 IWineD3DSwapChainImpl *swapchain = NULL;
2057 HRESULT hr;
2058 DWORD state;
2059 unsigned int i;
2061 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2062 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2063 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2065 /* TODO: Test if OpenGL is compiled in and loaded */
2067 TRACE("(%p) : Creating stateblock\n", This);
2068 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2069 hr = IWineD3DDevice_CreateStateBlock(iface,
2070 WINED3DSBT_INIT,
2071 (IWineD3DStateBlock **)&This->stateBlock,
2072 NULL);
2073 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2074 WARN("Failed to create stateblock\n");
2075 goto err_out;
2077 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2078 This->updateStateBlock = This->stateBlock;
2079 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2081 hr = allocate_shader_constants(This->updateStateBlock);
2082 if (WINED3D_OK != hr) {
2083 goto err_out;
2086 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2087 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2089 This->NumberOfPalettes = 1;
2090 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2091 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2092 ERR("Out of memory!\n");
2093 goto err_out;
2095 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2096 if(!This->palettes[0]) {
2097 ERR("Out of memory!\n");
2098 goto err_out;
2100 for (i = 0; i < 256; ++i) {
2101 This->palettes[0][i].peRed = 0xFF;
2102 This->palettes[0][i].peGreen = 0xFF;
2103 This->palettes[0][i].peBlue = 0xFF;
2104 This->palettes[0][i].peFlags = 0xFF;
2106 This->currentPalette = 0;
2108 /* Initialize the texture unit mapping to a 1:1 mapping */
2109 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2110 if (state < GL_LIMITS(fragment_samplers)) {
2111 This->texUnitMap[state] = state;
2112 This->rev_tex_unit_map[state] = state;
2113 } else {
2114 This->texUnitMap[state] = -1;
2115 This->rev_tex_unit_map[state] = -1;
2119 /* Setup the implicit swapchain */
2120 TRACE("Creating implicit swapchain\n");
2121 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2122 if (FAILED(hr) || !swapchain) {
2123 WARN("Failed to create implicit swapchain\n");
2124 goto err_out;
2127 This->NumberOfSwapChains = 1;
2128 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2129 if(!This->swapchains) {
2130 ERR("Out of memory!\n");
2131 goto err_out;
2133 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2135 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2136 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2137 This->render_targets[0] = swapchain->backBuffer[0];
2138 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2140 else {
2141 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2142 This->render_targets[0] = swapchain->frontBuffer;
2143 This->lastActiveRenderTarget = swapchain->frontBuffer;
2145 IWineD3DSurface_AddRef(This->render_targets[0]);
2146 This->activeContext = swapchain->context[0];
2147 This->lastThread = GetCurrentThreadId();
2149 /* Depth Stencil support */
2150 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2151 if (NULL != This->stencilBufferTarget) {
2152 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2155 hr = This->shader_backend->shader_alloc_private(iface);
2156 if(FAILED(hr)) {
2157 TRACE("Shader private data couldn't be allocated\n");
2158 goto err_out;
2160 hr = This->frag_pipe->alloc_private(iface);
2161 if(FAILED(hr)) {
2162 TRACE("Fragment pipeline private data couldn't be allocated\n");
2163 goto err_out;
2165 hr = This->blitter->alloc_private(iface);
2166 if(FAILED(hr)) {
2167 TRACE("Blitter private data couldn't be allocated\n");
2168 goto err_out;
2171 /* Set up some starting GL setup */
2173 /* Setup all the devices defaults */
2174 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2175 create_dummy_textures(This);
2177 ENTER_GL();
2179 { /* Set a default viewport */
2180 WINED3DVIEWPORT vp;
2181 vp.X = 0;
2182 vp.Y = 0;
2183 vp.Width = pPresentationParameters->BackBufferWidth;
2184 vp.Height = pPresentationParameters->BackBufferHeight;
2185 vp.MinZ = 0.0f;
2186 vp.MaxZ = 1.0f;
2187 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2190 /* Initialize the current view state */
2191 This->view_ident = 1;
2192 This->contexts[0]->last_was_rhw = 0;
2193 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2194 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2196 switch(wined3d_settings.offscreen_rendering_mode) {
2197 case ORM_FBO:
2198 case ORM_PBUFFER:
2199 This->offscreenBuffer = GL_BACK;
2200 break;
2202 case ORM_BACKBUFFER:
2204 if(This->activeContext->aux_buffers > 0) {
2205 TRACE("Using auxilliary buffer for offscreen rendering\n");
2206 This->offscreenBuffer = GL_AUX0;
2207 } else {
2208 TRACE("Using back buffer for offscreen rendering\n");
2209 This->offscreenBuffer = GL_BACK;
2214 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2215 LEAVE_GL();
2217 /* Clear the screen */
2218 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2219 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2220 0x00, 1.0, 0);
2222 This->d3d_initialized = TRUE;
2224 if(wined3d_settings.logo) {
2225 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2227 This->highest_dirty_ps_const = 0;
2228 This->highest_dirty_vs_const = 0;
2229 return WINED3D_OK;
2231 err_out:
2232 HeapFree(GetProcessHeap(), 0, This->render_targets);
2233 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2234 HeapFree(GetProcessHeap(), 0, This->swapchains);
2235 This->NumberOfSwapChains = 0;
2236 if(This->palettes) {
2237 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2238 HeapFree(GetProcessHeap(), 0, This->palettes);
2240 This->NumberOfPalettes = 0;
2241 if(swapchain) {
2242 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2244 if(This->stateBlock) {
2245 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2246 This->stateBlock = NULL;
2248 if (This->blit_priv) {
2249 This->blitter->free_private(iface);
2251 if (This->fragment_priv) {
2252 This->frag_pipe->free_private(iface);
2254 if (This->shader_priv) {
2255 This->shader_backend->shader_free_private(iface);
2257 return hr;
2260 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2262 IWineD3DSwapChainImpl *swapchain = NULL;
2263 HRESULT hr;
2265 /* Setup the implicit swapchain */
2266 TRACE("Creating implicit swapchain\n");
2267 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2268 if (FAILED(hr) || !swapchain) {
2269 WARN("Failed to create implicit swapchain\n");
2270 goto err_out;
2273 This->NumberOfSwapChains = 1;
2274 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2275 if(!This->swapchains) {
2276 ERR("Out of memory!\n");
2277 goto err_out;
2279 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2280 return WINED3D_OK;
2282 err_out:
2283 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2284 return hr;
2287 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2289 int sampler;
2290 UINT i;
2291 TRACE("(%p)\n", This);
2293 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2295 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2296 * it was created. Thus make sure a context is active for the glDelete* calls
2298 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2300 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2302 TRACE("Deleting high order patches\n");
2303 for(i = 0; i < PATCHMAP_SIZE; i++) {
2304 struct list *e1, *e2;
2305 struct WineD3DRectPatch *patch;
2306 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2307 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2308 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2312 /* Delete the palette conversion shader if it is around */
2313 if(This->paletteConversionShader) {
2314 ENTER_GL();
2315 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2316 LEAVE_GL();
2317 This->paletteConversionShader = 0;
2320 /* Delete the pbuffer context if there is any */
2321 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2323 /* Delete the mouse cursor texture */
2324 if(This->cursorTexture) {
2325 ENTER_GL();
2326 glDeleteTextures(1, &This->cursorTexture);
2327 LEAVE_GL();
2328 This->cursorTexture = 0;
2331 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2332 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2334 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2335 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2338 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2339 * private data, it might contain opengl pointers
2341 if(This->depth_blt_texture) {
2342 glDeleteTextures(1, &This->depth_blt_texture);
2343 This->depth_blt_texture = 0;
2345 if (This->depth_blt_rb) {
2346 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2347 This->depth_blt_rb = 0;
2348 This->depth_blt_rb_w = 0;
2349 This->depth_blt_rb_h = 0;
2352 /* Release the update stateblock */
2353 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2354 if(This->updateStateBlock != This->stateBlock)
2355 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2357 This->updateStateBlock = NULL;
2359 { /* because were not doing proper internal refcounts releasing the primary state block
2360 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2361 to set this->stateBlock = NULL; first */
2362 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2363 This->stateBlock = NULL;
2365 /* Release the stateblock */
2366 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2367 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2371 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2372 This->blitter->free_private(iface);
2373 This->frag_pipe->free_private(iface);
2374 This->shader_backend->shader_free_private(iface);
2376 /* Release the buffers (with sanity checks)*/
2377 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2378 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2379 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2380 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2382 This->stencilBufferTarget = NULL;
2384 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2385 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2386 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2388 TRACE("Setting rendertarget to NULL\n");
2389 This->render_targets[0] = NULL;
2391 if (This->auto_depth_stencil_buffer) {
2392 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2393 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2395 This->auto_depth_stencil_buffer = NULL;
2398 for(i=0; i < This->NumberOfSwapChains; i++) {
2399 TRACE("Releasing the implicit swapchain %d\n", i);
2400 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2401 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2405 HeapFree(GetProcessHeap(), 0, This->swapchains);
2406 This->swapchains = NULL;
2407 This->NumberOfSwapChains = 0;
2409 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2410 HeapFree(GetProcessHeap(), 0, This->palettes);
2411 This->palettes = NULL;
2412 This->NumberOfPalettes = 0;
2414 HeapFree(GetProcessHeap(), 0, This->render_targets);
2415 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2416 This->render_targets = NULL;
2417 This->draw_buffers = NULL;
2419 This->d3d_initialized = FALSE;
2420 return WINED3D_OK;
2423 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2425 unsigned int i;
2427 for(i=0; i < This->NumberOfSwapChains; i++) {
2428 TRACE("Releasing the implicit swapchain %d\n", i);
2429 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2430 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2434 HeapFree(GetProcessHeap(), 0, This->swapchains);
2435 This->swapchains = NULL;
2436 This->NumberOfSwapChains = 0;
2437 return WINED3D_OK;
2440 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2441 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2442 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2444 * There is no way to deactivate thread safety once it is enabled.
2446 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2447 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2449 /*For now just store the flag(needed in case of ddraw) */
2450 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2452 return;
2455 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2456 DEVMODEW devmode;
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2458 LONG ret;
2459 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2460 RECT clip_rc;
2462 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2464 /* Resize the screen even without a window:
2465 * The app could have unset it with SetCooperativeLevel, but not called
2466 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2467 * but we don't have any hwnd
2470 memset(&devmode, 0, sizeof(devmode));
2471 devmode.dmSize = sizeof(devmode);
2472 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2473 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2474 devmode.dmPelsWidth = pMode->Width;
2475 devmode.dmPelsHeight = pMode->Height;
2477 devmode.dmDisplayFrequency = pMode->RefreshRate;
2478 if (pMode->RefreshRate != 0) {
2479 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2482 /* Only change the mode if necessary */
2483 if( (This->ddraw_width == pMode->Width) &&
2484 (This->ddraw_height == pMode->Height) &&
2485 (This->ddraw_format == pMode->Format) &&
2486 (pMode->RefreshRate == 0) ) {
2487 return WINED3D_OK;
2490 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2491 if (ret != DISP_CHANGE_SUCCESSFUL) {
2492 if(devmode.dmDisplayFrequency != 0) {
2493 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2494 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2495 devmode.dmDisplayFrequency = 0;
2496 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2498 if(ret != DISP_CHANGE_SUCCESSFUL) {
2499 return WINED3DERR_NOTAVAILABLE;
2503 /* Store the new values */
2504 This->ddraw_width = pMode->Width;
2505 This->ddraw_height = pMode->Height;
2506 This->ddraw_format = pMode->Format;
2508 /* And finally clip mouse to our screen */
2509 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2510 ClipCursor(&clip_rc);
2512 return WINED3D_OK;
2515 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2517 *ppD3D= This->wineD3D;
2518 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2519 IWineD3D_AddRef(*ppD3D);
2520 return WINED3D_OK;
2523 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2526 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2527 (This->adapter->TextureRam/(1024*1024)),
2528 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2529 /* return simulated texture memory left */
2530 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2535 /*****
2536 * Get / Set FVF
2537 *****/
2538 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2541 /* Update the current state block */
2542 This->updateStateBlock->changed.fvf = TRUE;
2544 if(This->updateStateBlock->fvf == fvf) {
2545 TRACE("Application is setting the old fvf over, nothing to do\n");
2546 return WINED3D_OK;
2549 This->updateStateBlock->fvf = fvf;
2550 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2552 return WINED3D_OK;
2556 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2558 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2559 *pfvf = This->stateBlock->fvf;
2560 return WINED3D_OK;
2563 /*****
2564 * Get / Set Stream Source
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 IWineD3DVertexBuffer *oldSrc;
2570 if (StreamNumber >= MAX_STREAMS) {
2571 WARN("Stream out of range %d\n", StreamNumber);
2572 return WINED3DERR_INVALIDCALL;
2573 } else if(OffsetInBytes & 0x3) {
2574 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2575 return WINED3DERR_INVALIDCALL;
2578 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2579 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2581 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2583 if(oldSrc == pStreamData &&
2584 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2585 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2586 TRACE("Application is setting the old values over, nothing to do\n");
2587 return WINED3D_OK;
2590 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2591 if (pStreamData) {
2592 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2593 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2596 /* Handle recording of state blocks */
2597 if (This->isRecordingState) {
2598 TRACE("Recording... not performing anything\n");
2599 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2600 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2601 return WINED3D_OK;
2604 /* Need to do a getParent and pass the references up */
2605 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2606 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2607 so for now, just count internally */
2608 if (pStreamData != NULL) {
2609 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2610 InterlockedIncrement(&vbImpl->bindCount);
2611 IWineD3DVertexBuffer_AddRef(pStreamData);
2613 if (oldSrc != NULL) {
2614 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2615 IWineD3DVertexBuffer_Release(oldSrc);
2618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2620 return WINED3D_OK;
2623 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2624 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2626 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2627 This->stateBlock->streamSource[StreamNumber],
2628 This->stateBlock->streamOffset[StreamNumber],
2629 This->stateBlock->streamStride[StreamNumber]);
2631 if (StreamNumber >= MAX_STREAMS) {
2632 WARN("Stream out of range %d\n", StreamNumber);
2633 return WINED3DERR_INVALIDCALL;
2635 *pStream = This->stateBlock->streamSource[StreamNumber];
2636 *pStride = This->stateBlock->streamStride[StreamNumber];
2637 if (pOffset) {
2638 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2641 if (*pStream != NULL) {
2642 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2644 return WINED3D_OK;
2647 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2648 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2649 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2650 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2652 /* Verify input at least in d3d9 this is invalid*/
2653 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2654 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2655 return WINED3DERR_INVALIDCALL;
2657 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2658 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2659 return WINED3DERR_INVALIDCALL;
2661 if( Divider == 0 ){
2662 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2663 return WINED3DERR_INVALIDCALL;
2666 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2667 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2669 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2670 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2672 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2673 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2674 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2677 return WINED3D_OK;
2680 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2681 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2683 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2684 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2686 TRACE("(%p) : returning %d\n", This, *Divider);
2688 return WINED3D_OK;
2691 /*****
2692 * Get / Set & Multiply Transform
2693 *****/
2694 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2695 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2697 /* Most of this routine, comments included copied from ddraw tree initially: */
2698 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2700 /* Handle recording of state blocks */
2701 if (This->isRecordingState) {
2702 TRACE("Recording... not performing anything\n");
2703 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2704 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2705 return WINED3D_OK;
2709 * If the new matrix is the same as the current one,
2710 * we cut off any further processing. this seems to be a reasonable
2711 * optimization because as was noticed, some apps (warcraft3 for example)
2712 * tend towards setting the same matrix repeatedly for some reason.
2714 * From here on we assume that the new matrix is different, wherever it matters.
2716 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2717 TRACE("The app is setting the same matrix over again\n");
2718 return WINED3D_OK;
2719 } else {
2720 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2724 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2725 where ViewMat = Camera space, WorldMat = world space.
2727 In OpenGL, camera and world space is combined into GL_MODELVIEW
2728 matrix. The Projection matrix stay projection matrix.
2731 /* Capture the times we can just ignore the change for now */
2732 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2733 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2734 /* Handled by the state manager */
2737 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2738 return WINED3D_OK;
2741 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2743 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2744 *pMatrix = This->stateBlock->transforms[State];
2745 return WINED3D_OK;
2748 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2749 WINED3DMATRIX *mat = NULL;
2750 WINED3DMATRIX temp;
2752 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2753 * below means it will be recorded in a state block change, but it
2754 * works regardless where it is recorded.
2755 * If this is found to be wrong, change to StateBlock.
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2760 if (State < HIGHEST_TRANSFORMSTATE)
2762 mat = &This->updateStateBlock->transforms[State];
2763 } else {
2764 FIXME("Unhandled transform state!!\n");
2767 multiply_matrix(&temp, mat, pMatrix);
2769 /* Apply change via set transform - will reapply to eg. lights this way */
2770 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2773 /*****
2774 * Get / Set Light
2775 *****/
2776 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2777 you can reference any indexes you want as long as that number max are enabled at any
2778 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2779 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2780 but when recording, just build a chain pretty much of commands to be replayed. */
2782 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2783 float rho;
2784 PLIGHTINFOEL *object = NULL;
2785 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2786 struct list *e;
2788 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2789 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2791 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2792 * the gl driver.
2794 if(!pLight) {
2795 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2796 return WINED3DERR_INVALIDCALL;
2799 switch(pLight->Type) {
2800 case WINED3DLIGHT_POINT:
2801 case WINED3DLIGHT_SPOT:
2802 case WINED3DLIGHT_PARALLELPOINT:
2803 case WINED3DLIGHT_GLSPOT:
2804 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2805 * most wanted
2807 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2808 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2809 return WINED3DERR_INVALIDCALL;
2811 break;
2813 case WINED3DLIGHT_DIRECTIONAL:
2814 /* Ignores attenuation */
2815 break;
2817 default:
2818 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2819 return WINED3DERR_INVALIDCALL;
2822 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2823 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2824 if(object->OriginalIndex == Index) break;
2825 object = NULL;
2828 if(!object) {
2829 TRACE("Adding new light\n");
2830 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2831 if(!object) {
2832 ERR("Out of memory error when allocating a light\n");
2833 return E_OUTOFMEMORY;
2835 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2836 object->glIndex = -1;
2837 object->OriginalIndex = Index;
2838 object->changed = TRUE;
2841 /* Initialize the object */
2842 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,
2843 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2844 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2845 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2846 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2847 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2848 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2850 /* Save away the information */
2851 object->OriginalParms = *pLight;
2853 switch (pLight->Type) {
2854 case WINED3DLIGHT_POINT:
2855 /* Position */
2856 object->lightPosn[0] = pLight->Position.x;
2857 object->lightPosn[1] = pLight->Position.y;
2858 object->lightPosn[2] = pLight->Position.z;
2859 object->lightPosn[3] = 1.0f;
2860 object->cutoff = 180.0f;
2861 /* FIXME: Range */
2862 break;
2864 case WINED3DLIGHT_DIRECTIONAL:
2865 /* Direction */
2866 object->lightPosn[0] = -pLight->Direction.x;
2867 object->lightPosn[1] = -pLight->Direction.y;
2868 object->lightPosn[2] = -pLight->Direction.z;
2869 object->lightPosn[3] = 0.0;
2870 object->exponent = 0.0f;
2871 object->cutoff = 180.0f;
2872 break;
2874 case WINED3DLIGHT_SPOT:
2875 /* Position */
2876 object->lightPosn[0] = pLight->Position.x;
2877 object->lightPosn[1] = pLight->Position.y;
2878 object->lightPosn[2] = pLight->Position.z;
2879 object->lightPosn[3] = 1.0;
2881 /* Direction */
2882 object->lightDirn[0] = pLight->Direction.x;
2883 object->lightDirn[1] = pLight->Direction.y;
2884 object->lightDirn[2] = pLight->Direction.z;
2885 object->lightDirn[3] = 1.0;
2888 * opengl-ish and d3d-ish spot lights use too different models for the
2889 * light "intensity" as a function of the angle towards the main light direction,
2890 * so we only can approximate very roughly.
2891 * however spot lights are rather rarely used in games (if ever used at all).
2892 * furthermore if still used, probably nobody pays attention to such details.
2894 if (pLight->Falloff == 0) {
2895 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2896 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2897 * will always be 1.0 for both of them, and we don't have to care for the
2898 * rest of the rather complex calculation
2900 object->exponent = 0;
2901 } else {
2902 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2903 if (rho < 0.0001) rho = 0.0001f;
2904 object->exponent = -0.3/log(cos(rho/2));
2906 if (object->exponent > 128.0) {
2907 object->exponent = 128.0;
2909 object->cutoff = pLight->Phi*90/M_PI;
2911 /* FIXME: Range */
2912 break;
2914 default:
2915 FIXME("Unrecognized light type %d\n", pLight->Type);
2918 /* Update the live definitions if the light is currently assigned a glIndex */
2919 if (object->glIndex != -1 && !This->isRecordingState) {
2920 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2922 return WINED3D_OK;
2925 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2926 PLIGHTINFOEL *lightInfo = NULL;
2927 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2928 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2929 struct list *e;
2930 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2932 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2933 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2934 if(lightInfo->OriginalIndex == Index) break;
2935 lightInfo = NULL;
2938 if (lightInfo == NULL) {
2939 TRACE("Light information requested but light not defined\n");
2940 return WINED3DERR_INVALIDCALL;
2943 *pLight = lightInfo->OriginalParms;
2944 return WINED3D_OK;
2947 /*****
2948 * Get / Set Light Enable
2949 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2950 *****/
2951 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2952 PLIGHTINFOEL *lightInfo = NULL;
2953 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2954 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2955 struct list *e;
2956 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2958 /* Tests show true = 128...not clear why */
2959 Enable = Enable? 128: 0;
2961 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2962 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2963 if(lightInfo->OriginalIndex == Index) break;
2964 lightInfo = NULL;
2966 TRACE("Found light: %p\n", lightInfo);
2968 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2969 if (lightInfo == NULL) {
2971 TRACE("Light enabled requested but light not defined, so defining one!\n");
2972 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2974 /* Search for it again! Should be fairly quick as near head of list */
2975 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2976 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2977 if(lightInfo->OriginalIndex == Index) break;
2978 lightInfo = NULL;
2980 if (lightInfo == NULL) {
2981 FIXME("Adding default lights has failed dismally\n");
2982 return WINED3DERR_INVALIDCALL;
2986 lightInfo->enabledChanged = TRUE;
2987 if(!Enable) {
2988 if(lightInfo->glIndex != -1) {
2989 if(!This->isRecordingState) {
2990 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2993 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2994 lightInfo->glIndex = -1;
2995 } else {
2996 TRACE("Light already disabled, nothing to do\n");
2998 lightInfo->enabled = FALSE;
2999 } else {
3000 lightInfo->enabled = TRUE;
3001 if (lightInfo->glIndex != -1) {
3002 /* nop */
3003 TRACE("Nothing to do as light was enabled\n");
3004 } else {
3005 int i;
3006 /* Find a free gl light */
3007 for(i = 0; i < This->maxConcurrentLights; i++) {
3008 if(This->stateBlock->activeLights[i] == NULL) {
3009 This->stateBlock->activeLights[i] = lightInfo;
3010 lightInfo->glIndex = i;
3011 break;
3014 if(lightInfo->glIndex == -1) {
3015 /* Our tests show that Windows returns D3D_OK in this situation, even with
3016 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3017 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3018 * as well for those lights.
3020 * TODO: Test how this affects rendering
3022 FIXME("Too many concurrently active lights\n");
3023 return WINED3D_OK;
3026 /* i == lightInfo->glIndex */
3027 if(!This->isRecordingState) {
3028 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3033 return WINED3D_OK;
3036 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3038 PLIGHTINFOEL *lightInfo = NULL;
3039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3040 struct list *e;
3041 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3042 TRACE("(%p) : for idx(%d)\n", This, Index);
3044 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3045 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3046 if(lightInfo->OriginalIndex == Index) break;
3047 lightInfo = NULL;
3050 if (lightInfo == NULL) {
3051 TRACE("Light enabled state requested but light not defined\n");
3052 return WINED3DERR_INVALIDCALL;
3054 /* true is 128 according to SetLightEnable */
3055 *pEnable = lightInfo->enabled ? 128 : 0;
3056 return WINED3D_OK;
3059 /*****
3060 * Get / Set Clip Planes
3061 *****/
3062 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3064 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3066 /* Validate Index */
3067 if (Index >= GL_LIMITS(clipplanes)) {
3068 TRACE("Application has requested clipplane this device doesn't support\n");
3069 return WINED3DERR_INVALIDCALL;
3072 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3074 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3075 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3076 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3077 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3078 TRACE("Application is setting old values over, nothing to do\n");
3079 return WINED3D_OK;
3082 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3083 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3084 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3085 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3087 /* Handle recording of state blocks */
3088 if (This->isRecordingState) {
3089 TRACE("Recording... not performing anything\n");
3090 return WINED3D_OK;
3093 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3095 return WINED3D_OK;
3098 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3099 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3100 TRACE("(%p) : for idx %d\n", This, Index);
3102 /* Validate Index */
3103 if (Index >= GL_LIMITS(clipplanes)) {
3104 TRACE("Application has requested clipplane this device doesn't support\n");
3105 return WINED3DERR_INVALIDCALL;
3108 pPlane[0] = This->stateBlock->clipplane[Index][0];
3109 pPlane[1] = This->stateBlock->clipplane[Index][1];
3110 pPlane[2] = This->stateBlock->clipplane[Index][2];
3111 pPlane[3] = This->stateBlock->clipplane[Index][3];
3112 return WINED3D_OK;
3115 /*****
3116 * Get / Set Clip Plane Status
3117 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3118 *****/
3119 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3120 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3121 FIXME("(%p) : stub\n", This);
3122 if (NULL == pClipStatus) {
3123 return WINED3DERR_INVALIDCALL;
3125 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3126 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3127 return WINED3D_OK;
3130 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3131 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3132 FIXME("(%p) : stub\n", This);
3133 if (NULL == pClipStatus) {
3134 return WINED3DERR_INVALIDCALL;
3136 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3137 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3138 return WINED3D_OK;
3141 /*****
3142 * Get / Set Material
3143 *****/
3144 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3145 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 This->updateStateBlock->changed.material = TRUE;
3148 This->updateStateBlock->material = *pMaterial;
3150 /* Handle recording of state blocks */
3151 if (This->isRecordingState) {
3152 TRACE("Recording... not performing anything\n");
3153 return WINED3D_OK;
3156 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3157 return WINED3D_OK;
3160 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3161 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 *pMaterial = This->updateStateBlock->material;
3163 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3164 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3165 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3166 pMaterial->Ambient.b, pMaterial->Ambient.a);
3167 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3168 pMaterial->Specular.b, pMaterial->Specular.a);
3169 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3170 pMaterial->Emissive.b, pMaterial->Emissive.a);
3171 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3173 return WINED3D_OK;
3176 /*****
3177 * Get / Set Indices
3178 *****/
3179 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3181 IWineD3DIndexBuffer *oldIdxs;
3183 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3184 oldIdxs = This->updateStateBlock->pIndexData;
3186 This->updateStateBlock->changed.indices = TRUE;
3187 This->updateStateBlock->pIndexData = pIndexData;
3189 /* Handle recording of state blocks */
3190 if (This->isRecordingState) {
3191 TRACE("Recording... not performing anything\n");
3192 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3193 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3194 return WINED3D_OK;
3197 if(oldIdxs != pIndexData) {
3198 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3199 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3200 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3202 return WINED3D_OK;
3205 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3206 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 *ppIndexData = This->stateBlock->pIndexData;
3210 /* up ref count on ppindexdata */
3211 if (*ppIndexData) {
3212 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3213 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3214 }else{
3215 TRACE("(%p) No index data set\n", This);
3217 TRACE("Returning %p\n", *ppIndexData);
3219 return WINED3D_OK;
3222 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3223 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3224 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 TRACE("(%p)->(%d)\n", This, BaseIndex);
3227 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3228 TRACE("Application is setting the old value over, nothing to do\n");
3229 return WINED3D_OK;
3232 This->updateStateBlock->baseVertexIndex = BaseIndex;
3234 if (This->isRecordingState) {
3235 TRACE("Recording... not performing anything\n");
3236 return WINED3D_OK;
3238 /* The base vertex index affects the stream sources */
3239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3240 return WINED3D_OK;
3243 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3245 TRACE("(%p) : base_index %p\n", This, base_index);
3247 *base_index = This->stateBlock->baseVertexIndex;
3249 TRACE("Returning %u\n", *base_index);
3251 return WINED3D_OK;
3254 /*****
3255 * Get / Set Viewports
3256 *****/
3257 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3258 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3260 TRACE("(%p)\n", This);
3261 This->updateStateBlock->changed.viewport = TRUE;
3262 This->updateStateBlock->viewport = *pViewport;
3264 /* Handle recording of state blocks */
3265 if (This->isRecordingState) {
3266 TRACE("Recording... not performing anything\n");
3267 return WINED3D_OK;
3270 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3271 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3274 return WINED3D_OK;
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p)\n", This);
3281 *pViewport = This->stateBlock->viewport;
3282 return WINED3D_OK;
3285 /*****
3286 * Get / Set Render States
3287 * TODO: Verify against dx9 definitions
3288 *****/
3289 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 DWORD oldValue = This->stateBlock->renderState[State];
3294 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3296 This->updateStateBlock->changed.renderState[State] = TRUE;
3297 This->updateStateBlock->renderState[State] = Value;
3299 /* Handle recording of state blocks */
3300 if (This->isRecordingState) {
3301 TRACE("Recording... not performing anything\n");
3302 return WINED3D_OK;
3305 /* Compared here and not before the assignment to allow proper stateblock recording */
3306 if(Value == oldValue) {
3307 TRACE("Application is setting the old value over, nothing to do\n");
3308 } else {
3309 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3312 return WINED3D_OK;
3315 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3316 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3317 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3318 *pValue = This->stateBlock->renderState[State];
3319 return WINED3D_OK;
3322 /*****
3323 * Get / Set Sampler States
3324 * TODO: Verify against dx9 definitions
3325 *****/
3327 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 DWORD oldValue;
3331 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3332 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3334 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3335 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3338 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3339 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3340 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3343 * SetSampler is designed to allow for more than the standard up to 8 textures
3344 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3345 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3347 * http://developer.nvidia.com/object/General_FAQ.html#t6
3349 * There are two new settings for GForce
3350 * the sampler one:
3351 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3352 * and the texture one:
3353 * GL_MAX_TEXTURE_COORDS_ARB.
3354 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3355 ******************/
3357 oldValue = This->stateBlock->samplerState[Sampler][Type];
3358 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3359 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3361 /* Handle recording of state blocks */
3362 if (This->isRecordingState) {
3363 TRACE("Recording... not performing anything\n");
3364 return WINED3D_OK;
3367 if(oldValue == Value) {
3368 TRACE("Application is setting the old value over, nothing to do\n");
3369 return WINED3D_OK;
3372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3374 return WINED3D_OK;
3377 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3380 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3381 This, Sampler, debug_d3dsamplerstate(Type), Type);
3383 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3384 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3387 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3388 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3389 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3391 *Value = This->stateBlock->samplerState[Sampler][Type];
3392 TRACE("(%p) : Returning %#x\n", This, *Value);
3394 return WINED3D_OK;
3397 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3400 This->updateStateBlock->changed.scissorRect = TRUE;
3401 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3402 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3403 return WINED3D_OK;
3405 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3407 if(This->isRecordingState) {
3408 TRACE("Recording... not performing anything\n");
3409 return WINED3D_OK;
3412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3414 return WINED3D_OK;
3417 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3420 *pRect = This->updateStateBlock->scissorRect;
3421 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3422 return WINED3D_OK;
3425 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3427 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3429 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3431 This->updateStateBlock->vertexDecl = pDecl;
3432 This->updateStateBlock->changed.vertexDecl = TRUE;
3434 if (This->isRecordingState) {
3435 TRACE("Recording... not performing anything\n");
3436 return WINED3D_OK;
3437 } else if(pDecl == oldDecl) {
3438 /* Checked after the assignment to allow proper stateblock recording */
3439 TRACE("Application is setting the old declaration over, nothing to do\n");
3440 return WINED3D_OK;
3443 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3444 return WINED3D_OK;
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3452 *ppDecl = This->stateBlock->vertexDecl;
3453 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3454 return WINED3D_OK;
3457 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3458 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3459 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3461 This->updateStateBlock->vertexShader = pShader;
3462 This->updateStateBlock->changed.vertexShader = TRUE;
3464 if (This->isRecordingState) {
3465 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3466 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3467 TRACE("Recording... not performing anything\n");
3468 return WINED3D_OK;
3469 } else if(oldShader == pShader) {
3470 /* Checked here to allow proper stateblock recording */
3471 TRACE("App is setting the old shader over, nothing to do\n");
3472 return WINED3D_OK;
3475 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3476 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3477 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3479 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3481 return WINED3D_OK;
3484 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3487 if (NULL == ppShader) {
3488 return WINED3DERR_INVALIDCALL;
3490 *ppShader = This->stateBlock->vertexShader;
3491 if( NULL != *ppShader)
3492 IWineD3DVertexShader_AddRef(*ppShader);
3494 TRACE("(%p) : returning %p\n", This, *ppShader);
3495 return WINED3D_OK;
3498 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3499 IWineD3DDevice *iface,
3500 UINT start,
3501 CONST BOOL *srcData,
3502 UINT count) {
3504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3505 int i, cnt = min(count, MAX_CONST_B - start);
3507 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3508 iface, srcData, start, count);
3510 if (srcData == NULL || cnt < 0)
3511 return WINED3DERR_INVALIDCALL;
3513 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3514 for (i = 0; i < cnt; i++)
3515 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3517 for (i = start; i < cnt + start; ++i) {
3518 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3521 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3523 return WINED3D_OK;
3526 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3527 IWineD3DDevice *iface,
3528 UINT start,
3529 BOOL *dstData,
3530 UINT count) {
3532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3533 int cnt = min(count, MAX_CONST_B - start);
3535 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3536 iface, dstData, start, count);
3538 if (dstData == NULL || cnt < 0)
3539 return WINED3DERR_INVALIDCALL;
3541 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3542 return WINED3D_OK;
3545 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3546 IWineD3DDevice *iface,
3547 UINT start,
3548 CONST int *srcData,
3549 UINT count) {
3551 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3552 int i, cnt = min(count, MAX_CONST_I - start);
3554 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3555 iface, srcData, start, count);
3557 if (srcData == NULL || cnt < 0)
3558 return WINED3DERR_INVALIDCALL;
3560 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3561 for (i = 0; i < cnt; i++)
3562 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3563 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3565 for (i = start; i < cnt + start; ++i) {
3566 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3569 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3571 return WINED3D_OK;
3574 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3575 IWineD3DDevice *iface,
3576 UINT start,
3577 int *dstData,
3578 UINT count) {
3580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3581 int cnt = min(count, MAX_CONST_I - start);
3583 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3584 iface, dstData, start, count);
3586 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3587 return WINED3DERR_INVALIDCALL;
3589 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3590 return WINED3D_OK;
3593 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3594 IWineD3DDevice *iface,
3595 UINT start,
3596 CONST float *srcData,
3597 UINT count) {
3599 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3600 int i;
3602 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3603 iface, srcData, start, count);
3605 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3606 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3607 return WINED3DERR_INVALIDCALL;
3609 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3610 if(TRACE_ON(d3d)) {
3611 for (i = 0; i < count; i++)
3612 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3613 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3616 for (i = start; i < count + start; ++i) {
3617 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3618 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3619 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3620 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3621 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3623 ptr->idx[ptr->count++] = i;
3624 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3630 return WINED3D_OK;
3633 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3634 IWineD3DDevice *iface,
3635 UINT start,
3636 CONST float *srcData,
3637 UINT count) {
3639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3640 int i;
3642 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3643 iface, srcData, start, count);
3645 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3646 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3647 return WINED3DERR_INVALIDCALL;
3649 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3650 if(TRACE_ON(d3d)) {
3651 for (i = 0; i < count; i++)
3652 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3653 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3656 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3657 * context. On a context switch the old context will be fully dirtified
3659 memset(This->activeContext->vshader_const_dirty + start, 1,
3660 sizeof(*This->activeContext->vshader_const_dirty) * count);
3661 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3665 return WINED3D_OK;
3668 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3669 IWineD3DDevice *iface,
3670 UINT start,
3671 float *dstData,
3672 UINT count) {
3674 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3675 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3677 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3678 iface, dstData, start, count);
3680 if (dstData == NULL || cnt < 0)
3681 return WINED3DERR_INVALIDCALL;
3683 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3684 return WINED3D_OK;
3687 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3688 DWORD i;
3689 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3694 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3695 int i = This->rev_tex_unit_map[unit];
3696 int j = This->texUnitMap[stage];
3698 This->texUnitMap[stage] = unit;
3699 if (i != -1 && i != stage) {
3700 This->texUnitMap[i] = -1;
3703 This->rev_tex_unit_map[unit] = stage;
3704 if (j != -1 && j != unit) {
3705 This->rev_tex_unit_map[j] = -1;
3709 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3710 int i;
3712 for (i = 0; i < MAX_TEXTURES; ++i) {
3713 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3714 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3715 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3716 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3717 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3718 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3719 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3720 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3722 if (color_op == WINED3DTOP_DISABLE) {
3723 /* Not used, and disable higher stages */
3724 while (i < MAX_TEXTURES) {
3725 This->fixed_function_usage_map[i] = FALSE;
3726 ++i;
3728 break;
3731 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3732 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3733 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3734 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3735 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3736 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3737 This->fixed_function_usage_map[i] = TRUE;
3738 } else {
3739 This->fixed_function_usage_map[i] = FALSE;
3742 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3743 This->fixed_function_usage_map[i+1] = TRUE;
3748 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3749 int i, tex;
3751 device_update_fixed_function_usage_map(This);
3753 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3754 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3755 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3756 if (!This->fixed_function_usage_map[i]) continue;
3758 if (This->texUnitMap[i] != i) {
3759 device_map_stage(This, i, i);
3760 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3761 markTextureStagesDirty(This, i);
3764 return;
3767 /* Now work out the mapping */
3768 tex = 0;
3769 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3770 if (!This->fixed_function_usage_map[i]) continue;
3772 if (This->texUnitMap[i] != tex) {
3773 device_map_stage(This, i, tex);
3774 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3775 markTextureStagesDirty(This, i);
3778 ++tex;
3782 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3783 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3784 int i;
3786 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3787 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3788 device_map_stage(This, i, i);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3790 if (i < MAX_TEXTURES) {
3791 markTextureStagesDirty(This, i);
3797 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3798 int current_mapping = This->rev_tex_unit_map[unit];
3800 if (current_mapping == -1) {
3801 /* Not currently used */
3802 return TRUE;
3805 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3806 /* Used by a fragment sampler */
3808 if (!pshader_sampler_tokens) {
3809 /* No pixel shader, check fixed function */
3810 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3813 /* Pixel shader, check the shader's sampler map */
3814 return !pshader_sampler_tokens[current_mapping];
3817 /* Used by a vertex sampler */
3818 return !vshader_sampler_tokens[current_mapping];
3821 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3822 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3823 DWORD *pshader_sampler_tokens = NULL;
3824 int start = GL_LIMITS(combined_samplers) - 1;
3825 int i;
3827 if (ps) {
3828 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3830 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3831 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3832 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3835 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3836 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3837 if (vshader_sampler_tokens[i]) {
3838 if (This->texUnitMap[vsampler_idx] != -1) {
3839 /* Already mapped somewhere */
3840 continue;
3843 while (start >= 0) {
3844 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3845 device_map_stage(This, vsampler_idx, start);
3846 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3848 --start;
3849 break;
3852 --start;
3858 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3859 BOOL vs = use_vs(This);
3860 BOOL ps = use_ps(This);
3862 * Rules are:
3863 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3864 * that would be really messy and require shader recompilation
3865 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3866 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3868 if (ps) {
3869 device_map_psamplers(This);
3870 } else {
3871 device_map_fixed_function_samplers(This);
3874 if (vs) {
3875 device_map_vsamplers(This, ps);
3879 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3881 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3882 This->updateStateBlock->pixelShader = pShader;
3883 This->updateStateBlock->changed.pixelShader = TRUE;
3885 /* Handle recording of state blocks */
3886 if (This->isRecordingState) {
3887 TRACE("Recording... not performing anything\n");
3890 if (This->isRecordingState) {
3891 TRACE("Recording... not performing anything\n");
3892 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3893 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3894 return WINED3D_OK;
3897 if(pShader == oldShader) {
3898 TRACE("App is setting the old pixel shader over, nothing to do\n");
3899 return WINED3D_OK;
3902 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3903 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3905 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3906 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3908 return WINED3D_OK;
3911 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3912 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3914 if (NULL == ppShader) {
3915 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3916 return WINED3DERR_INVALIDCALL;
3919 *ppShader = This->stateBlock->pixelShader;
3920 if (NULL != *ppShader) {
3921 IWineD3DPixelShader_AddRef(*ppShader);
3923 TRACE("(%p) : returning %p\n", This, *ppShader);
3924 return WINED3D_OK;
3927 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3928 IWineD3DDevice *iface,
3929 UINT start,
3930 CONST BOOL *srcData,
3931 UINT count) {
3933 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3934 int i, cnt = min(count, MAX_CONST_B - start);
3936 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3937 iface, srcData, start, count);
3939 if (srcData == NULL || cnt < 0)
3940 return WINED3DERR_INVALIDCALL;
3942 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3943 for (i = 0; i < cnt; i++)
3944 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3946 for (i = start; i < cnt + start; ++i) {
3947 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3950 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3952 return WINED3D_OK;
3955 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3956 IWineD3DDevice *iface,
3957 UINT start,
3958 BOOL *dstData,
3959 UINT count) {
3961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3962 int cnt = min(count, MAX_CONST_B - start);
3964 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3965 iface, dstData, start, count);
3967 if (dstData == NULL || cnt < 0)
3968 return WINED3DERR_INVALIDCALL;
3970 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3971 return WINED3D_OK;
3974 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3975 IWineD3DDevice *iface,
3976 UINT start,
3977 CONST int *srcData,
3978 UINT count) {
3980 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3981 int i, cnt = min(count, MAX_CONST_I - start);
3983 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3984 iface, srcData, start, count);
3986 if (srcData == NULL || cnt < 0)
3987 return WINED3DERR_INVALIDCALL;
3989 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3990 for (i = 0; i < cnt; i++)
3991 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3992 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3994 for (i = start; i < cnt + start; ++i) {
3995 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3998 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4004 IWineD3DDevice *iface,
4005 UINT start,
4006 int *dstData,
4007 UINT count) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 int cnt = min(count, MAX_CONST_I - start);
4012 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4013 iface, dstData, start, count);
4015 if (dstData == NULL || cnt < 0)
4016 return WINED3DERR_INVALIDCALL;
4018 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4019 return WINED3D_OK;
4022 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4023 IWineD3DDevice *iface,
4024 UINT start,
4025 CONST float *srcData,
4026 UINT count) {
4028 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4029 int i;
4031 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4032 iface, srcData, start, count);
4034 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4035 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4036 return WINED3DERR_INVALIDCALL;
4038 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4039 if(TRACE_ON(d3d)) {
4040 for (i = 0; i < count; i++)
4041 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4042 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4045 for (i = start; i < count + start; ++i) {
4046 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4047 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4048 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4049 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4050 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4052 ptr->idx[ptr->count++] = i;
4053 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4057 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4059 return WINED3D_OK;
4062 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4063 IWineD3DDevice *iface,
4064 UINT start,
4065 CONST float *srcData,
4066 UINT count) {
4068 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4069 int i;
4071 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4072 iface, srcData, start, count);
4074 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4075 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4076 return WINED3DERR_INVALIDCALL;
4078 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4079 if(TRACE_ON(d3d)) {
4080 for (i = 0; i < count; i++)
4081 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4082 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4085 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4086 * context. On a context switch the old context will be fully dirtified
4088 memset(This->activeContext->pshader_const_dirty + start, 1,
4089 sizeof(*This->activeContext->pshader_const_dirty) * count);
4090 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4092 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4094 return WINED3D_OK;
4097 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4098 IWineD3DDevice *iface,
4099 UINT start,
4100 float *dstData,
4101 UINT count) {
4103 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4104 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4106 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4107 iface, dstData, start, count);
4109 if (dstData == NULL || cnt < 0)
4110 return WINED3DERR_INVALIDCALL;
4112 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4113 return WINED3D_OK;
4116 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4117 static HRESULT
4118 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4119 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4120 unsigned int i;
4121 DWORD DestFVF = dest->fvf;
4122 WINED3DVIEWPORT vp;
4123 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4124 BOOL doClip;
4125 int numTextures;
4127 if (lpStrideData->u.s.normal.lpData) {
4128 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4131 if (lpStrideData->u.s.position.lpData == NULL) {
4132 ERR("Source has no position mask\n");
4133 return WINED3DERR_INVALIDCALL;
4136 /* We might access VBOs from this code, so hold the lock */
4137 ENTER_GL();
4139 if (dest->resource.allocatedMemory == NULL) {
4140 /* This may happen if we do direct locking into a vbo. Unlikely,
4141 * but theoretically possible(ddraw processvertices test)
4143 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4144 if(!dest->resource.allocatedMemory) {
4145 LEAVE_GL();
4146 ERR("Out of memory\n");
4147 return E_OUTOFMEMORY;
4149 if(dest->vbo) {
4150 void *src;
4151 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4152 checkGLcall("glBindBufferARB");
4153 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4154 if(src) {
4155 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4157 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4158 checkGLcall("glUnmapBufferARB");
4162 /* Get a pointer into the destination vbo(create one if none exists) and
4163 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4165 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4166 dest->Flags |= VBFLAG_CREATEVBO;
4167 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4170 if(dest->vbo) {
4171 unsigned char extrabytes = 0;
4172 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4173 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4174 * this may write 4 extra bytes beyond the area that should be written
4176 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4177 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4178 if(!dest_conv_addr) {
4179 ERR("Out of memory\n");
4180 /* Continue without storing converted vertices */
4182 dest_conv = dest_conv_addr;
4185 /* Should I clip?
4186 * a) WINED3DRS_CLIPPING is enabled
4187 * b) WINED3DVOP_CLIP is passed
4189 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4190 static BOOL warned = FALSE;
4192 * The clipping code is not quite correct. Some things need
4193 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4194 * so disable clipping for now.
4195 * (The graphics in Half-Life are broken, and my processvertices
4196 * test crashes with IDirect3DDevice3)
4197 doClip = TRUE;
4199 doClip = FALSE;
4200 if(!warned) {
4201 warned = TRUE;
4202 FIXME("Clipping is broken and disabled for now\n");
4204 } else doClip = FALSE;
4205 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4207 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4208 WINED3DTS_VIEW,
4209 &view_mat);
4210 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4211 WINED3DTS_PROJECTION,
4212 &proj_mat);
4213 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4214 WINED3DTS_WORLDMATRIX(0),
4215 &world_mat);
4217 TRACE("View mat:\n");
4218 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);
4219 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);
4220 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);
4221 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);
4223 TRACE("Proj mat:\n");
4224 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);
4225 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);
4226 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);
4227 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);
4229 TRACE("World mat:\n");
4230 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);
4231 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);
4232 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);
4233 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);
4235 /* Get the viewport */
4236 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4237 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4238 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4240 multiply_matrix(&mat,&view_mat,&world_mat);
4241 multiply_matrix(&mat,&proj_mat,&mat);
4243 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4245 for (i = 0; i < dwCount; i+= 1) {
4246 unsigned int tex_index;
4248 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4249 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4250 /* The position first */
4251 float *p =
4252 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4253 float x, y, z, rhw;
4254 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4256 /* Multiplication with world, view and projection matrix */
4257 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);
4258 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);
4259 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);
4260 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);
4262 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4264 /* WARNING: The following things are taken from d3d7 and were not yet checked
4265 * against d3d8 or d3d9!
4268 /* Clipping conditions: From msdn
4270 * A vertex is clipped if it does not match the following requirements
4271 * -rhw < x <= rhw
4272 * -rhw < y <= rhw
4273 * 0 < z <= rhw
4274 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4276 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4277 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4281 if( !doClip ||
4282 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4283 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4284 ( rhw > eps ) ) ) {
4286 /* "Normal" viewport transformation (not clipped)
4287 * 1) The values are divided by rhw
4288 * 2) The y axis is negative, so multiply it with -1
4289 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4290 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4291 * 4) Multiply x with Width/2 and add Width/2
4292 * 5) The same for the height
4293 * 6) Add the viewpoint X and Y to the 2D coordinates and
4294 * The minimum Z value to z
4295 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4297 * Well, basically it's simply a linear transformation into viewport
4298 * coordinates
4301 x /= rhw;
4302 y /= rhw;
4303 z /= rhw;
4305 y *= -1;
4307 x *= vp.Width / 2;
4308 y *= vp.Height / 2;
4309 z *= vp.MaxZ - vp.MinZ;
4311 x += vp.Width / 2 + vp.X;
4312 y += vp.Height / 2 + vp.Y;
4313 z += vp.MinZ;
4315 rhw = 1 / rhw;
4316 } else {
4317 /* That vertex got clipped
4318 * Contrary to OpenGL it is not dropped completely, it just
4319 * undergoes a different calculation.
4321 TRACE("Vertex got clipped\n");
4322 x += rhw;
4323 y += rhw;
4325 x /= 2;
4326 y /= 2;
4328 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4329 * outside of the main vertex buffer memory. That needs some more
4330 * investigation...
4334 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4337 ( (float *) dest_ptr)[0] = x;
4338 ( (float *) dest_ptr)[1] = y;
4339 ( (float *) dest_ptr)[2] = z;
4340 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4342 dest_ptr += 3 * sizeof(float);
4344 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4345 dest_ptr += sizeof(float);
4348 if(dest_conv) {
4349 float w = 1 / rhw;
4350 ( (float *) dest_conv)[0] = x * w;
4351 ( (float *) dest_conv)[1] = y * w;
4352 ( (float *) dest_conv)[2] = z * w;
4353 ( (float *) dest_conv)[3] = w;
4355 dest_conv += 3 * sizeof(float);
4357 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4358 dest_conv += sizeof(float);
4362 if (DestFVF & WINED3DFVF_PSIZE) {
4363 dest_ptr += sizeof(DWORD);
4364 if(dest_conv) dest_conv += sizeof(DWORD);
4366 if (DestFVF & WINED3DFVF_NORMAL) {
4367 float *normal =
4368 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4369 /* AFAIK this should go into the lighting information */
4370 FIXME("Didn't expect the destination to have a normal\n");
4371 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4372 if(dest_conv) {
4373 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4377 if (DestFVF & WINED3DFVF_DIFFUSE) {
4378 DWORD *color_d =
4379 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4380 if(!color_d) {
4381 static BOOL warned = FALSE;
4383 if(!warned) {
4384 ERR("No diffuse color in source, but destination has one\n");
4385 warned = TRUE;
4388 *( (DWORD *) dest_ptr) = 0xffffffff;
4389 dest_ptr += sizeof(DWORD);
4391 if(dest_conv) {
4392 *( (DWORD *) dest_conv) = 0xffffffff;
4393 dest_conv += sizeof(DWORD);
4396 else {
4397 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4398 if(dest_conv) {
4399 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4400 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4401 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4402 dest_conv += sizeof(DWORD);
4407 if (DestFVF & WINED3DFVF_SPECULAR) {
4408 /* What's the color value in the feedback buffer? */
4409 DWORD *color_s =
4410 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4411 if(!color_s) {
4412 static BOOL warned = FALSE;
4414 if(!warned) {
4415 ERR("No specular color in source, but destination has one\n");
4416 warned = TRUE;
4419 *( (DWORD *) dest_ptr) = 0xFF000000;
4420 dest_ptr += sizeof(DWORD);
4422 if(dest_conv) {
4423 *( (DWORD *) dest_conv) = 0xFF000000;
4424 dest_conv += sizeof(DWORD);
4427 else {
4428 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4429 if(dest_conv) {
4430 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4431 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4432 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4433 dest_conv += sizeof(DWORD);
4438 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4439 float *tex_coord =
4440 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4441 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4442 if(!tex_coord) {
4443 ERR("No source texture, but destination requests one\n");
4444 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4445 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4447 else {
4448 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4449 if(dest_conv) {
4450 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4456 if(dest_conv) {
4457 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4458 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4459 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4460 dwCount * get_flexible_vertex_size(DestFVF),
4461 dest_conv_addr));
4462 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4463 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4466 LEAVE_GL();
4468 return WINED3D_OK;
4470 #undef copy_and_next
4472 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4474 WineDirect3DVertexStridedData strided;
4475 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4476 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4478 if(pVertexDecl) {
4479 ERR("Output vertex declaration not implemented yet\n");
4482 /* Need any context to write to the vbo. */
4483 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4485 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4486 * control the streamIsUP flag, thus restore it afterwards.
4488 This->stateBlock->streamIsUP = FALSE;
4489 memset(&strided, 0, sizeof(strided));
4490 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4491 This->stateBlock->streamIsUP = streamWasUP;
4493 if(vbo || SrcStartIndex) {
4494 unsigned int i;
4495 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4496 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4498 * Also get the start index in, but only loop over all elements if there's something to add at all.
4500 #define FIXSRC(type) \
4501 if(strided.u.s.type.VBO) { \
4502 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4503 strided.u.s.type.VBO = 0; \
4504 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4505 ENTER_GL(); \
4506 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4507 vb->vbo = 0; \
4508 LEAVE_GL(); \
4510 if(strided.u.s.type.lpData) { \
4511 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4513 FIXSRC(position);
4514 FIXSRC(blendWeights);
4515 FIXSRC(blendMatrixIndices);
4516 FIXSRC(normal);
4517 FIXSRC(pSize);
4518 FIXSRC(diffuse);
4519 FIXSRC(specular);
4520 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4521 FIXSRC(texCoords[i]);
4523 FIXSRC(position2);
4524 FIXSRC(normal2);
4525 FIXSRC(tangent);
4526 FIXSRC(binormal);
4527 FIXSRC(tessFactor);
4528 FIXSRC(fog);
4529 FIXSRC(depth);
4530 FIXSRC(sample);
4531 #undef FIXSRC
4534 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4537 /*****
4538 * Get / Set Texture Stage States
4539 * TODO: Verify against dx9 definitions
4540 *****/
4541 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4543 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4545 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4547 if (Stage >= MAX_TEXTURES) {
4548 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4549 return WINED3D_OK;
4552 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4553 This->updateStateBlock->textureState[Stage][Type] = Value;
4555 if (This->isRecordingState) {
4556 TRACE("Recording... not performing anything\n");
4557 return WINED3D_OK;
4560 /* Checked after the assignments to allow proper stateblock recording */
4561 if(oldValue == Value) {
4562 TRACE("App is setting the old value over, nothing to do\n");
4563 return WINED3D_OK;
4566 if(Stage > This->stateBlock->lowest_disabled_stage &&
4567 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4568 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4569 * Changes in other states are important on disabled stages too
4571 return WINED3D_OK;
4574 if(Type == WINED3DTSS_COLOROP) {
4575 int i;
4577 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4578 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4579 * they have to be disabled
4581 * The current stage is dirtified below.
4583 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4584 TRACE("Additionally dirtifying stage %d\n", i);
4585 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4587 This->stateBlock->lowest_disabled_stage = Stage;
4588 TRACE("New lowest disabled: %d\n", Stage);
4589 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4590 /* Previously disabled stage enabled. Stages above it may need enabling
4591 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4592 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4594 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4597 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4598 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4599 break;
4601 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4602 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4604 This->stateBlock->lowest_disabled_stage = i;
4605 TRACE("New lowest disabled: %d\n", i);
4609 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4611 return WINED3D_OK;
4614 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4615 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4616 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4617 *pValue = This->updateStateBlock->textureState[Stage][Type];
4618 return WINED3D_OK;
4621 /*****
4622 * Get / Set Texture
4623 *****/
4624 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4625 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4626 IWineD3DBaseTexture *oldTexture;
4628 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4630 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4631 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4634 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4635 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4636 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4639 oldTexture = This->updateStateBlock->textures[Stage];
4641 if(pTexture != NULL) {
4642 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4644 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4645 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4646 return WINED3DERR_INVALIDCALL;
4648 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4651 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4652 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4654 This->updateStateBlock->changed.textures[Stage] = TRUE;
4655 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4656 This->updateStateBlock->textures[Stage] = pTexture;
4658 /* Handle recording of state blocks */
4659 if (This->isRecordingState) {
4660 TRACE("Recording... not performing anything\n");
4661 return WINED3D_OK;
4664 if(oldTexture == pTexture) {
4665 TRACE("App is setting the same texture again, nothing to do\n");
4666 return WINED3D_OK;
4669 /** NOTE: MSDN says that setTexture increases the reference count,
4670 * and that the application must set the texture back to null (or have a leaky application),
4671 * This means we should pass the refcount up to the parent
4672 *******************************/
4673 if (NULL != This->updateStateBlock->textures[Stage]) {
4674 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4675 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4677 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4678 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4679 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4680 * so the COLOROP and ALPHAOP have to be dirtified.
4682 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4683 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4685 if(bindCount == 1) {
4686 new->baseTexture.sampler = Stage;
4688 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4692 if (NULL != oldTexture) {
4693 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4694 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4696 IWineD3DBaseTexture_Release(oldTexture);
4697 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4699 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4702 if(bindCount && old->baseTexture.sampler == Stage) {
4703 int i;
4704 /* Have to do a search for the other sampler(s) where the texture is bound to
4705 * Shouldn't happen as long as apps bind a texture only to one stage
4707 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4708 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4709 if(This->updateStateBlock->textures[i] == oldTexture) {
4710 old->baseTexture.sampler = i;
4711 break;
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4719 return WINED3D_OK;
4722 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4725 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4727 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4728 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4731 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4732 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4733 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4736 *ppTexture=This->stateBlock->textures[Stage];
4737 if (*ppTexture)
4738 IWineD3DBaseTexture_AddRef(*ppTexture);
4740 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4742 return WINED3D_OK;
4745 /*****
4746 * Get Back Buffer
4747 *****/
4748 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4749 IWineD3DSurface **ppBackBuffer) {
4750 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4751 IWineD3DSwapChain *swapChain;
4752 HRESULT hr;
4754 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4756 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4757 if (hr == WINED3D_OK) {
4758 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4759 IWineD3DSwapChain_Release(swapChain);
4760 } else {
4761 *ppBackBuffer = NULL;
4763 return hr;
4766 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4768 WARN("(%p) : stub, calling idirect3d for now\n", This);
4769 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4772 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4774 IWineD3DSwapChain *swapChain;
4775 HRESULT hr;
4777 if(iSwapChain > 0) {
4778 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4779 if (hr == WINED3D_OK) {
4780 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4781 IWineD3DSwapChain_Release(swapChain);
4782 } else {
4783 FIXME("(%p) Error getting display mode\n", This);
4785 } else {
4786 /* Don't read the real display mode,
4787 but return the stored mode instead. X11 can't change the color
4788 depth, and some apps are pretty angry if they SetDisplayMode from
4789 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4791 Also don't relay to the swapchain because with ddraw it's possible
4792 that there isn't a swapchain at all */
4793 pMode->Width = This->ddraw_width;
4794 pMode->Height = This->ddraw_height;
4795 pMode->Format = This->ddraw_format;
4796 pMode->RefreshRate = 0;
4797 hr = WINED3D_OK;
4800 return hr;
4803 /*****
4804 * Stateblock related functions
4805 *****/
4807 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4808 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4809 IWineD3DStateBlockImpl *object;
4810 HRESULT temp_result;
4811 int i;
4813 TRACE("(%p)\n", This);
4815 if (This->isRecordingState) {
4816 return WINED3DERR_INVALIDCALL;
4819 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4820 if (NULL == object ) {
4821 FIXME("(%p)Error allocating memory for stateblock\n", This);
4822 return E_OUTOFMEMORY;
4824 TRACE("(%p) created object %p\n", This, object);
4825 object->wineD3DDevice= This;
4826 /** FIXME: object->parent = parent; **/
4827 object->parent = NULL;
4828 object->blockType = WINED3DSBT_RECORDED;
4829 object->ref = 1;
4830 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4832 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4833 list_init(&object->lightMap[i]);
4836 temp_result = allocate_shader_constants(object);
4837 if (WINED3D_OK != temp_result)
4838 return temp_result;
4840 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4841 This->updateStateBlock = object;
4842 This->isRecordingState = TRUE;
4844 TRACE("(%p) recording stateblock %p\n",This , object);
4845 return WINED3D_OK;
4848 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4850 unsigned int i, j;
4851 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4853 if (!This->isRecordingState) {
4854 FIXME("(%p) not recording! returning error\n", This);
4855 *ppStateBlock = NULL;
4856 return WINED3DERR_INVALIDCALL;
4859 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4860 if(object->changed.renderState[i]) {
4861 object->contained_render_states[object->num_contained_render_states] = i;
4862 object->num_contained_render_states++;
4865 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4866 if(object->changed.transform[i]) {
4867 object->contained_transform_states[object->num_contained_transform_states] = i;
4868 object->num_contained_transform_states++;
4871 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4872 if(object->changed.vertexShaderConstantsF[i]) {
4873 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4874 object->num_contained_vs_consts_f++;
4877 for(i = 0; i < MAX_CONST_I; i++) {
4878 if(object->changed.vertexShaderConstantsI[i]) {
4879 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4880 object->num_contained_vs_consts_i++;
4883 for(i = 0; i < MAX_CONST_B; i++) {
4884 if(object->changed.vertexShaderConstantsB[i]) {
4885 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4886 object->num_contained_vs_consts_b++;
4889 for(i = 0; i < MAX_CONST_I; i++) {
4890 if(object->changed.pixelShaderConstantsI[i]) {
4891 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4892 object->num_contained_ps_consts_i++;
4895 for(i = 0; i < MAX_CONST_B; i++) {
4896 if(object->changed.pixelShaderConstantsB[i]) {
4897 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4898 object->num_contained_ps_consts_b++;
4901 for(i = 0; i < MAX_TEXTURES; i++) {
4902 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4903 if(object->changed.textureState[i][j]) {
4904 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4905 object->contained_tss_states[object->num_contained_tss_states].state = j;
4906 object->num_contained_tss_states++;
4910 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4911 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4912 if(object->changed.samplerState[i][j]) {
4913 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4914 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4915 object->num_contained_sampler_states++;
4920 *ppStateBlock = (IWineD3DStateBlock*) object;
4921 This->isRecordingState = FALSE;
4922 This->updateStateBlock = This->stateBlock;
4923 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4924 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4925 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4926 return WINED3D_OK;
4929 /*****
4930 * Scene related functions
4931 *****/
4932 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4933 /* At the moment we have no need for any functionality at the beginning
4934 of a scene */
4935 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4936 TRACE("(%p)\n", This);
4938 if(This->inScene) {
4939 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4940 return WINED3DERR_INVALIDCALL;
4942 This->inScene = TRUE;
4943 return WINED3D_OK;
4946 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4947 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4948 TRACE("(%p)\n", This);
4950 if(!This->inScene) {
4951 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4952 return WINED3DERR_INVALIDCALL;
4955 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4956 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4957 glFlush();
4958 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4959 * fails
4962 This->inScene = FALSE;
4963 return WINED3D_OK;
4966 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4967 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4968 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4969 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4970 IWineD3DSwapChain *swapChain = NULL;
4971 int i;
4972 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4974 TRACE("(%p) Presenting the frame\n", This);
4976 for(i = 0 ; i < swapchains ; i ++) {
4978 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4979 TRACE("presentinng chain %d, %p\n", i, swapChain);
4980 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4981 IWineD3DSwapChain_Release(swapChain);
4984 return WINED3D_OK;
4987 /* Not called from the VTable (internal subroutine) */
4988 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4989 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4990 float Z, DWORD Stencil) {
4991 GLbitfield glMask = 0;
4992 unsigned int i;
4993 WINED3DRECT curRect;
4994 RECT vp_rect;
4995 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4996 UINT drawable_width, drawable_height;
4997 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4998 IWineD3DSwapChainImpl *swapchain = NULL;
5000 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5001 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5002 * for the cleared parts, and the untouched parts.
5004 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5005 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5006 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5007 * checking all this if the dest surface is in the drawable anyway.
5009 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5010 while(1) {
5011 if(vp->X != 0 || vp->Y != 0 ||
5012 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5013 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5014 break;
5016 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5017 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5018 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5019 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5020 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5021 break;
5023 if(Count > 0 && pRects && (
5024 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5025 pRects[0].x2 < target->currentDesc.Width ||
5026 pRects[0].y2 < target->currentDesc.Height)) {
5027 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5028 break;
5030 break;
5034 target->get_drawable_size(target, &drawable_width, &drawable_height);
5036 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5037 ENTER_GL();
5039 /* Only set the values up once, as they are not changing */
5040 if (Flags & WINED3DCLEAR_STENCIL) {
5041 glClearStencil(Stencil);
5042 checkGLcall("glClearStencil");
5043 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5044 glStencilMask(0xFFFFFFFF);
5047 if (Flags & WINED3DCLEAR_ZBUFFER) {
5048 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5049 glDepthMask(GL_TRUE);
5050 glClearDepth(Z);
5051 checkGLcall("glClearDepth");
5052 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5053 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5055 if (vp->X != 0 || vp->Y != 0 ||
5056 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5057 surface_load_ds_location(This->stencilBufferTarget, location);
5059 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5060 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5061 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5062 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5063 surface_load_ds_location(This->stencilBufferTarget, location);
5065 else if (Count > 0 && pRects && (
5066 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5067 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5068 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5069 surface_load_ds_location(This->stencilBufferTarget, location);
5073 if (Flags & WINED3DCLEAR_TARGET) {
5074 TRACE("Clearing screen with glClear to color %x\n", Color);
5075 glClearColor(D3DCOLOR_R(Color),
5076 D3DCOLOR_G(Color),
5077 D3DCOLOR_B(Color),
5078 D3DCOLOR_A(Color));
5079 checkGLcall("glClearColor");
5081 /* Clear ALL colors! */
5082 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5083 glMask = glMask | GL_COLOR_BUFFER_BIT;
5086 vp_rect.left = vp->X;
5087 vp_rect.top = vp->Y;
5088 vp_rect.right = vp->X + vp->Width;
5089 vp_rect.bottom = vp->Y + vp->Height;
5090 if (!(Count > 0 && pRects)) {
5091 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5092 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5094 if(This->render_offscreen) {
5095 glScissor(vp_rect.left, vp_rect.top,
5096 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5097 } else {
5098 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5099 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5101 checkGLcall("glScissor");
5102 glClear(glMask);
5103 checkGLcall("glClear");
5104 } else {
5105 /* Now process each rect in turn */
5106 for (i = 0; i < Count; i++) {
5107 /* Note gl uses lower left, width/height */
5108 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5109 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5110 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5112 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5113 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5114 curRect.x1, (target->currentDesc.Height - curRect.y2),
5115 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5117 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5118 * The rectangle is not cleared, no error is returned, but further rectanlges are
5119 * still cleared if they are valid
5121 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5122 TRACE("Rectangle with negative dimensions, ignoring\n");
5123 continue;
5126 if(This->render_offscreen) {
5127 glScissor(curRect.x1, curRect.y1,
5128 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5129 } else {
5130 glScissor(curRect.x1, drawable_height - curRect.y2,
5131 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5133 checkGLcall("glScissor");
5135 glClear(glMask);
5136 checkGLcall("glClear");
5140 /* Restore the old values (why..?) */
5141 if (Flags & WINED3DCLEAR_STENCIL) {
5142 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5144 if (Flags & WINED3DCLEAR_TARGET) {
5145 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5146 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5147 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5148 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5149 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5151 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5152 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5154 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5155 /* TODO: Move the fbo logic into ModifyLocation() */
5156 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5157 target->Flags |= SFLAG_INTEXTURE;
5160 if (Flags & WINED3DCLEAR_ZBUFFER) {
5161 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5162 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5163 surface_modify_ds_location(This->stencilBufferTarget, location);
5166 LEAVE_GL();
5168 IWineD3DSurface_GetContainer( (IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5169 if (swapchain) {
5170 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5171 glFlush();
5173 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5176 return WINED3D_OK;
5179 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5180 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5181 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5182 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5184 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5185 Count, pRects, Flags, Color, Z, Stencil);
5187 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5188 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5189 /* TODO: What about depth stencil buffers without stencil bits? */
5190 return WINED3DERR_INVALIDCALL;
5193 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5196 /*****
5197 * Drawing functions
5198 *****/
5199 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5200 UINT PrimitiveCount) {
5202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5204 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5205 debug_d3dprimitivetype(PrimitiveType),
5206 StartVertex, PrimitiveCount);
5208 if(!This->stateBlock->vertexDecl) {
5209 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5210 return WINED3DERR_INVALIDCALL;
5213 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5214 if(This->stateBlock->streamIsUP) {
5215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5216 This->stateBlock->streamIsUP = FALSE;
5219 if(This->stateBlock->loadBaseVertexIndex != 0) {
5220 This->stateBlock->loadBaseVertexIndex = 0;
5221 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5223 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5224 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5225 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5226 return WINED3D_OK;
5229 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5230 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5231 WINED3DPRIMITIVETYPE PrimitiveType,
5232 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5234 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5235 UINT idxStride = 2;
5236 IWineD3DIndexBuffer *pIB;
5237 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5238 GLuint vbo;
5240 pIB = This->stateBlock->pIndexData;
5241 if (!pIB) {
5242 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5243 * without an index buffer set. (The first time at least...)
5244 * D3D8 simply dies, but I doubt it can do much harm to return
5245 * D3DERR_INVALIDCALL there as well. */
5246 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5247 return WINED3DERR_INVALIDCALL;
5250 if(!This->stateBlock->vertexDecl) {
5251 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5252 return WINED3DERR_INVALIDCALL;
5255 if(This->stateBlock->streamIsUP) {
5256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5257 This->stateBlock->streamIsUP = FALSE;
5259 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5261 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5262 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5263 minIndex, NumVertices, startIndex, primCount);
5265 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5266 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5267 idxStride = 2;
5268 } else {
5269 idxStride = 4;
5272 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5273 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5277 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5278 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5280 return WINED3D_OK;
5283 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5284 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5285 UINT VertexStreamZeroStride) {
5286 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5287 IWineD3DVertexBuffer *vb;
5289 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5290 debug_d3dprimitivetype(PrimitiveType),
5291 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5293 if(!This->stateBlock->vertexDecl) {
5294 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5295 return WINED3DERR_INVALIDCALL;
5298 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5299 vb = This->stateBlock->streamSource[0];
5300 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5301 if(vb) IWineD3DVertexBuffer_Release(vb);
5302 This->stateBlock->streamOffset[0] = 0;
5303 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5304 This->stateBlock->streamIsUP = TRUE;
5305 This->stateBlock->loadBaseVertexIndex = 0;
5307 /* TODO: Only mark dirty if drawing from a different UP address */
5308 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5310 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5311 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5313 /* MSDN specifies stream zero settings must be set to NULL */
5314 This->stateBlock->streamStride[0] = 0;
5315 This->stateBlock->streamSource[0] = NULL;
5317 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5318 * the new stream sources or use UP drawing again
5320 return WINED3D_OK;
5323 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5324 UINT MinVertexIndex, UINT NumVertices,
5325 UINT PrimitiveCount, CONST void* pIndexData,
5326 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5327 UINT VertexStreamZeroStride) {
5328 int idxStride;
5329 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5330 IWineD3DVertexBuffer *vb;
5331 IWineD3DIndexBuffer *ib;
5333 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5334 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5335 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5336 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5338 if(!This->stateBlock->vertexDecl) {
5339 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5340 return WINED3DERR_INVALIDCALL;
5343 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5344 idxStride = 2;
5345 } else {
5346 idxStride = 4;
5349 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5350 vb = This->stateBlock->streamSource[0];
5351 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5352 if(vb) IWineD3DVertexBuffer_Release(vb);
5353 This->stateBlock->streamIsUP = TRUE;
5354 This->stateBlock->streamOffset[0] = 0;
5355 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5357 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5358 This->stateBlock->baseVertexIndex = 0;
5359 This->stateBlock->loadBaseVertexIndex = 0;
5360 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5362 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5364 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5366 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5367 This->stateBlock->streamSource[0] = NULL;
5368 This->stateBlock->streamStride[0] = 0;
5369 ib = This->stateBlock->pIndexData;
5370 if(ib) {
5371 IWineD3DIndexBuffer_Release(ib);
5372 This->stateBlock->pIndexData = NULL;
5374 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5375 * SetStreamSource to specify a vertex buffer
5378 return WINED3D_OK;
5381 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5382 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5384 /* Mark the state dirty until we have nicer tracking
5385 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5386 * that value.
5388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5390 This->stateBlock->baseVertexIndex = 0;
5391 This->up_strided = DrawPrimStrideData;
5392 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5393 This->up_strided = NULL;
5394 return WINED3D_OK;
5397 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5398 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5399 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5401 /* Mark the state dirty until we have nicer tracking
5402 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5403 * that value.
5405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5407 This->stateBlock->streamIsUP = TRUE;
5408 This->stateBlock->baseVertexIndex = 0;
5409 This->up_strided = DrawPrimStrideData;
5410 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5411 This->up_strided = NULL;
5412 return WINED3D_OK;
5415 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5416 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5417 * not callable by the app directly no parameter validation checks are needed here.
5419 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5420 WINED3DLOCKED_BOX src;
5421 WINED3DLOCKED_BOX dst;
5422 HRESULT hr;
5423 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5425 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5426 * dirtification to improve loading performance.
5428 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5429 if(FAILED(hr)) return hr;
5430 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5431 if(FAILED(hr)) {
5432 IWineD3DVolume_UnlockBox(pSourceVolume);
5433 return hr;
5436 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5438 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5439 if(FAILED(hr)) {
5440 IWineD3DVolume_UnlockBox(pSourceVolume);
5441 } else {
5442 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5444 return hr;
5447 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5448 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5449 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5450 HRESULT hr = WINED3D_OK;
5451 WINED3DRESOURCETYPE sourceType;
5452 WINED3DRESOURCETYPE destinationType;
5453 int i ,levels;
5455 /* TODO: think about moving the code into IWineD3DBaseTexture */
5457 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5459 /* verify that the source and destination textures aren't NULL */
5460 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5461 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5462 This, pSourceTexture, pDestinationTexture);
5463 hr = WINED3DERR_INVALIDCALL;
5466 if (pSourceTexture == pDestinationTexture) {
5467 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5468 This, pSourceTexture, pDestinationTexture);
5469 hr = WINED3DERR_INVALIDCALL;
5471 /* Verify that the source and destination textures are the same type */
5472 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5473 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5475 if (sourceType != destinationType) {
5476 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5477 This);
5478 hr = WINED3DERR_INVALIDCALL;
5481 /* check that both textures have the identical numbers of levels */
5482 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5483 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5484 hr = WINED3DERR_INVALIDCALL;
5487 if (WINED3D_OK == hr) {
5489 /* Make sure that the destination texture is loaded */
5490 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5492 /* Update every surface level of the texture */
5493 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5495 switch (sourceType) {
5496 case WINED3DRTYPE_TEXTURE:
5498 IWineD3DSurface *srcSurface;
5499 IWineD3DSurface *destSurface;
5501 for (i = 0 ; i < levels ; ++i) {
5502 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5503 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5504 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5505 IWineD3DSurface_Release(srcSurface);
5506 IWineD3DSurface_Release(destSurface);
5507 if (WINED3D_OK != hr) {
5508 WARN("(%p) : Call to update surface failed\n", This);
5509 return hr;
5513 break;
5514 case WINED3DRTYPE_CUBETEXTURE:
5516 IWineD3DSurface *srcSurface;
5517 IWineD3DSurface *destSurface;
5518 WINED3DCUBEMAP_FACES faceType;
5520 for (i = 0 ; i < levels ; ++i) {
5521 /* Update each cube face */
5522 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5523 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5524 if (WINED3D_OK != hr) {
5525 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5526 } else {
5527 TRACE("Got srcSurface %p\n", srcSurface);
5529 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5530 if (WINED3D_OK != hr) {
5531 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5532 } else {
5533 TRACE("Got desrSurface %p\n", destSurface);
5535 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5536 IWineD3DSurface_Release(srcSurface);
5537 IWineD3DSurface_Release(destSurface);
5538 if (WINED3D_OK != hr) {
5539 WARN("(%p) : Call to update surface failed\n", This);
5540 return hr;
5545 break;
5547 case WINED3DRTYPE_VOLUMETEXTURE:
5549 IWineD3DVolume *srcVolume = NULL;
5550 IWineD3DVolume *destVolume = NULL;
5552 for (i = 0 ; i < levels ; ++i) {
5553 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5554 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5555 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5556 IWineD3DVolume_Release(srcVolume);
5557 IWineD3DVolume_Release(destVolume);
5558 if (WINED3D_OK != hr) {
5559 WARN("(%p) : Call to update volume failed\n", This);
5560 return hr;
5564 break;
5566 default:
5567 FIXME("(%p) : Unsupported source and destination type\n", This);
5568 hr = WINED3DERR_INVALIDCALL;
5572 return hr;
5575 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5576 IWineD3DSwapChain *swapChain;
5577 HRESULT hr;
5578 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5579 if(hr == WINED3D_OK) {
5580 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5581 IWineD3DSwapChain_Release(swapChain);
5583 return hr;
5586 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5587 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5588 IWineD3DBaseTextureImpl *texture;
5589 const GlPixelFormatDesc *gl_info;
5590 DWORD i;
5592 TRACE("(%p) : %p \n", This, pNumPasses);
5594 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5595 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5596 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5597 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5599 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5600 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5601 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5604 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5605 if(!texture) continue;
5606 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5607 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5609 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5610 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5611 return E_FAIL;
5613 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5614 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5615 return E_FAIL;
5617 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5618 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5619 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5620 return E_FAIL;
5624 /* return a sensible default */
5625 *pNumPasses = 1;
5627 TRACE("returning D3D_OK\n");
5628 return WINED3D_OK;
5631 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5633 int i;
5635 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5636 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5637 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5638 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5643 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5645 int j;
5646 UINT NewSize;
5647 PALETTEENTRY **palettes;
5649 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5651 if (PaletteNumber >= MAX_PALETTES) {
5652 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5653 return WINED3DERR_INVALIDCALL;
5656 if (PaletteNumber >= This->NumberOfPalettes) {
5657 NewSize = This->NumberOfPalettes;
5658 do {
5659 NewSize *= 2;
5660 } while(PaletteNumber >= NewSize);
5661 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5662 if (!palettes) {
5663 ERR("Out of memory!\n");
5664 return E_OUTOFMEMORY;
5666 This->palettes = palettes;
5667 This->NumberOfPalettes = NewSize;
5670 if (!This->palettes[PaletteNumber]) {
5671 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5672 if (!This->palettes[PaletteNumber]) {
5673 ERR("Out of memory!\n");
5674 return E_OUTOFMEMORY;
5678 for (j = 0; j < 256; ++j) {
5679 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5680 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5681 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5682 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5684 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5685 TRACE("(%p) : returning\n", This);
5686 return WINED3D_OK;
5689 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5691 int j;
5692 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5693 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5694 /* What happens in such situation isn't documented; Native seems to silently abort
5695 on such conditions. Return Invalid Call. */
5696 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5697 return WINED3DERR_INVALIDCALL;
5699 for (j = 0; j < 256; ++j) {
5700 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5701 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5702 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5703 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5705 TRACE("(%p) : returning\n", This);
5706 return WINED3D_OK;
5709 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5711 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5712 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5713 (tested with reference rasterizer). Return Invalid Call. */
5714 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5715 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5716 return WINED3DERR_INVALIDCALL;
5718 /*TODO: stateblocks */
5719 if (This->currentPalette != PaletteNumber) {
5720 This->currentPalette = PaletteNumber;
5721 dirtify_p8_texture_samplers(This);
5723 TRACE("(%p) : returning\n", This);
5724 return WINED3D_OK;
5727 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5728 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5729 if (PaletteNumber == NULL) {
5730 WARN("(%p) : returning Invalid Call\n", This);
5731 return WINED3DERR_INVALIDCALL;
5733 /*TODO: stateblocks */
5734 *PaletteNumber = This->currentPalette;
5735 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5736 return WINED3D_OK;
5739 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5741 static BOOL showFixmes = TRUE;
5742 if (showFixmes) {
5743 FIXME("(%p) : stub\n", This);
5744 showFixmes = FALSE;
5747 This->softwareVertexProcessing = bSoftware;
5748 return WINED3D_OK;
5752 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5754 static BOOL showFixmes = TRUE;
5755 if (showFixmes) {
5756 FIXME("(%p) : stub\n", This);
5757 showFixmes = FALSE;
5759 return This->softwareVertexProcessing;
5763 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5765 IWineD3DSwapChain *swapChain;
5766 HRESULT hr;
5768 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5770 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5771 if(hr == WINED3D_OK){
5772 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5773 IWineD3DSwapChain_Release(swapChain);
5774 }else{
5775 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5777 return hr;
5781 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5783 static BOOL showfixmes = TRUE;
5784 if(nSegments != 0.0f) {
5785 if( showfixmes) {
5786 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5787 showfixmes = FALSE;
5790 return WINED3D_OK;
5793 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5794 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5795 static BOOL showfixmes = TRUE;
5796 if( showfixmes) {
5797 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5798 showfixmes = FALSE;
5800 return 0.0f;
5803 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5804 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5805 /** TODO: remove casts to IWineD3DSurfaceImpl
5806 * NOTE: move code to surface to accomplish this
5807 ****************************************/
5808 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5809 int srcWidth, srcHeight;
5810 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5811 WINED3DFORMAT destFormat, srcFormat;
5812 UINT destSize;
5813 int srcLeft, destLeft, destTop;
5814 WINED3DPOOL srcPool, destPool;
5815 int offset = 0;
5816 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5817 glDescriptor *glDescription = NULL;
5818 GLenum dummy;
5819 int sampler;
5820 int bpp;
5821 CONVERT_TYPES convert = NO_CONVERSION;
5823 WINED3DSURFACE_DESC winedesc;
5825 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5826 memset(&winedesc, 0, sizeof(winedesc));
5827 winedesc.Width = &srcSurfaceWidth;
5828 winedesc.Height = &srcSurfaceHeight;
5829 winedesc.Pool = &srcPool;
5830 winedesc.Format = &srcFormat;
5832 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5834 winedesc.Width = &destSurfaceWidth;
5835 winedesc.Height = &destSurfaceHeight;
5836 winedesc.Pool = &destPool;
5837 winedesc.Format = &destFormat;
5838 winedesc.Size = &destSize;
5840 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5842 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5843 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5844 return WINED3DERR_INVALIDCALL;
5847 /* This call loads the opengl surface directly, instead of copying the surface to the
5848 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5849 * copy in sysmem and use regular surface loading.
5851 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5852 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5853 if(convert != NO_CONVERSION) {
5854 return IWineD3DSurface_BltFast(pDestinationSurface,
5855 pDestPoint ? pDestPoint->x : 0,
5856 pDestPoint ? pDestPoint->y : 0,
5857 pSourceSurface, (RECT *) pSourceRect, 0);
5860 if (destFormat == WINED3DFMT_UNKNOWN) {
5861 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5862 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5864 /* Get the update surface description */
5865 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5868 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5870 ENTER_GL();
5872 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5873 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5874 checkGLcall("glActiveTextureARB");
5877 /* Make sure the surface is loaded and up to date */
5878 IWineD3DSurface_PreLoad(pDestinationSurface);
5880 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5882 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5883 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5884 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5885 srcLeft = pSourceRect ? pSourceRect->left : 0;
5886 destLeft = pDestPoint ? pDestPoint->x : 0;
5887 destTop = pDestPoint ? pDestPoint->y : 0;
5890 /* This function doesn't support compressed textures
5891 the pitch is just bytesPerPixel * width */
5892 if(srcWidth != srcSurfaceWidth || srcLeft ){
5893 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5894 offset += srcLeft * pSrcSurface->bytesPerPixel;
5895 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5897 /* TODO DXT formats */
5899 if(pSourceRect != NULL && pSourceRect->top != 0){
5900 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5902 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5903 ,This
5904 ,glDescription->level
5905 ,destLeft
5906 ,destTop
5907 ,srcWidth
5908 ,srcHeight
5909 ,glDescription->glFormat
5910 ,glDescription->glType
5911 ,IWineD3DSurface_GetData(pSourceSurface)
5914 /* Sanity check */
5915 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5917 /* need to lock the surface to get the data */
5918 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5921 /* TODO: Cube and volume support */
5922 if(rowoffset != 0){
5923 /* not a whole row so we have to do it a line at a time */
5924 int j;
5926 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5927 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5929 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5931 glTexSubImage2D(glDescription->target
5932 ,glDescription->level
5933 ,destLeft
5935 ,srcWidth
5937 ,glDescription->glFormat
5938 ,glDescription->glType
5939 ,data /* could be quicker using */
5941 data += rowoffset;
5944 } else { /* Full width, so just write out the whole texture */
5946 if (WINED3DFMT_DXT1 == destFormat ||
5947 WINED3DFMT_DXT2 == destFormat ||
5948 WINED3DFMT_DXT3 == destFormat ||
5949 WINED3DFMT_DXT4 == destFormat ||
5950 WINED3DFMT_DXT5 == destFormat) {
5951 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5952 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5953 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5954 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5955 } if (destFormat != srcFormat) {
5956 FIXME("Updating mixed format compressed texture is not curretly support\n");
5957 } else {
5958 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5959 glDescription->level,
5960 glDescription->glFormatInternal,
5961 srcWidth,
5962 srcHeight,
5964 destSize,
5965 IWineD3DSurface_GetData(pSourceSurface));
5967 } else {
5968 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5972 } else {
5973 glTexSubImage2D(glDescription->target
5974 ,glDescription->level
5975 ,destLeft
5976 ,destTop
5977 ,srcWidth
5978 ,srcHeight
5979 ,glDescription->glFormat
5980 ,glDescription->glType
5981 ,IWineD3DSurface_GetData(pSourceSurface)
5985 checkGLcall("glTexSubImage2D");
5987 LEAVE_GL();
5989 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5990 sampler = This->rev_tex_unit_map[0];
5991 if (sampler != -1) {
5992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5995 return WINED3D_OK;
5998 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6000 struct WineD3DRectPatch *patch;
6001 unsigned int i;
6002 struct list *e;
6003 BOOL found;
6004 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6006 if(!(Handle || pRectPatchInfo)) {
6007 /* TODO: Write a test for the return value, thus the FIXME */
6008 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6009 return WINED3DERR_INVALIDCALL;
6012 if(Handle) {
6013 i = PATCHMAP_HASHFUNC(Handle);
6014 found = FALSE;
6015 LIST_FOR_EACH(e, &This->patches[i]) {
6016 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6017 if(patch->Handle == Handle) {
6018 found = TRUE;
6019 break;
6023 if(!found) {
6024 TRACE("Patch does not exist. Creating a new one\n");
6025 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6026 patch->Handle = Handle;
6027 list_add_head(&This->patches[i], &patch->entry);
6028 } else {
6029 TRACE("Found existing patch %p\n", patch);
6031 } else {
6032 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6033 * attributes we have to tesselate, read back, and draw. This needs a patch
6034 * management structure instance. Create one.
6036 * A possible improvement is to check if a vertex shader is used, and if not directly
6037 * draw the patch.
6039 FIXME("Drawing an uncached patch. This is slow\n");
6040 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6043 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6044 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6045 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6046 HRESULT hr;
6047 TRACE("Tesselation density or patch info changed, retesselating\n");
6049 if(pRectPatchInfo) {
6050 patch->RectPatchInfo = *pRectPatchInfo;
6052 patch->numSegs[0] = pNumSegs[0];
6053 patch->numSegs[1] = pNumSegs[1];
6054 patch->numSegs[2] = pNumSegs[2];
6055 patch->numSegs[3] = pNumSegs[3];
6057 hr = tesselate_rectpatch(This, patch);
6058 if(FAILED(hr)) {
6059 WARN("Patch tesselation failed\n");
6061 /* Do not release the handle to store the params of the patch */
6062 if(!Handle) {
6063 HeapFree(GetProcessHeap(), 0, patch);
6065 return hr;
6069 This->currentPatch = patch;
6070 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6071 This->currentPatch = NULL;
6073 /* Destroy uncached patches */
6074 if(!Handle) {
6075 HeapFree(GetProcessHeap(), 0, patch->mem);
6076 HeapFree(GetProcessHeap(), 0, patch);
6078 return WINED3D_OK;
6081 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6083 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6084 FIXME("(%p) : Stub\n", This);
6085 return WINED3D_OK;
6088 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 int i;
6091 struct WineD3DRectPatch *patch;
6092 struct list *e;
6093 TRACE("(%p) Handle(%d)\n", This, Handle);
6095 i = PATCHMAP_HASHFUNC(Handle);
6096 LIST_FOR_EACH(e, &This->patches[i]) {
6097 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6098 if(patch->Handle == Handle) {
6099 TRACE("Deleting patch %p\n", patch);
6100 list_remove(&patch->entry);
6101 HeapFree(GetProcessHeap(), 0, patch->mem);
6102 HeapFree(GetProcessHeap(), 0, patch);
6103 return WINED3D_OK;
6107 /* TODO: Write a test for the return value */
6108 FIXME("Attempt to destroy nonexistent patch\n");
6109 return WINED3DERR_INVALIDCALL;
6112 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6113 HRESULT hr;
6114 IWineD3DSwapChain *swapchain;
6116 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6117 if (SUCCEEDED(hr)) {
6118 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6119 return swapchain;
6122 return NULL;
6125 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 if (!*fbo) {
6129 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6130 checkGLcall("glGenFramebuffersEXT()");
6131 TRACE("Created FBO %d\n", *fbo);
6133 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6134 checkGLcall("glBindFramebuffer()");
6137 /* TODO: Handle stencil attachments */
6138 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6139 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6141 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6142 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6143 checkGLcall("glFramebufferRenderbufferEXT()");
6144 } else {
6145 IWineD3DBaseTextureImpl *texture_impl;
6146 GLenum texttarget, target;
6147 GLint old_binding = 0;
6149 texttarget = depth_stencil_impl->glDescription.target;
6150 if(texttarget == GL_TEXTURE_2D) {
6151 target = GL_TEXTURE_2D;
6152 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6153 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6154 target = GL_TEXTURE_RECTANGLE_ARB;
6155 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6156 } else {
6157 target = GL_TEXTURE_CUBE_MAP_ARB;
6158 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6161 IWineD3DSurface_PreLoad(depth_stencil);
6163 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6164 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6165 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6166 glBindTexture(target, old_binding);
6168 /* Update base texture states array */
6169 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6170 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6171 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6172 if (texture_impl->baseTexture.bindCount) {
6173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6176 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6179 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6180 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6181 checkGLcall("glFramebufferTexture2DEXT()");
6185 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6186 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6187 IWineD3DBaseTextureImpl *texture_impl;
6188 GLenum texttarget, target;
6189 GLint old_binding;
6191 texttarget = surface_impl->glDescription.target;
6192 if(texttarget == GL_TEXTURE_2D) {
6193 target = GL_TEXTURE_2D;
6194 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6195 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6196 target = GL_TEXTURE_RECTANGLE_ARB;
6197 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6198 } else {
6199 target = GL_TEXTURE_CUBE_MAP_ARB;
6200 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6203 IWineD3DSurface_PreLoad(surface);
6205 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6206 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6207 glBindTexture(target, old_binding);
6209 /* Update base texture states array */
6210 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6211 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6212 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6213 if (texture_impl->baseTexture.bindCount) {
6214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6217 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6220 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6221 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6223 checkGLcall("attach_surface_fbo");
6226 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6228 IWineD3DSwapChain *swapchain;
6230 swapchain = get_swapchain(surface);
6231 if (swapchain) {
6232 GLenum buffer;
6234 TRACE("Surface %p is onscreen\n", surface);
6236 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6237 ENTER_GL();
6238 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6239 buffer = surface_get_gl_buffer(surface, swapchain);
6240 glDrawBuffer(buffer);
6241 checkGLcall("glDrawBuffer()");
6242 } else {
6243 TRACE("Surface %p is offscreen\n", surface);
6245 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6246 ENTER_GL();
6247 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6248 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6249 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6250 checkGLcall("glFramebufferRenderbufferEXT");
6253 if (rect) {
6254 glEnable(GL_SCISSOR_TEST);
6255 if(!swapchain) {
6256 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6257 } else {
6258 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6259 rect->x2 - rect->x1, rect->y2 - rect->y1);
6261 checkGLcall("glScissor");
6262 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6263 } else {
6264 glDisable(GL_SCISSOR_TEST);
6266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6268 glDisable(GL_BLEND);
6269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6271 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6274 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6275 glClear(GL_COLOR_BUFFER_BIT);
6276 checkGLcall("glClear");
6278 if (This->render_offscreen) {
6279 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6280 } else {
6281 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6282 checkGLcall("glBindFramebuffer()");
6285 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6286 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6287 glDrawBuffer(GL_BACK);
6288 checkGLcall("glDrawBuffer()");
6291 LEAVE_GL();
6294 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6295 unsigned int r, g, b, a;
6296 DWORD ret;
6298 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6299 destfmt == WINED3DFMT_R8G8B8)
6300 return color;
6302 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6304 a = (color & 0xff000000) >> 24;
6305 r = (color & 0x00ff0000) >> 16;
6306 g = (color & 0x0000ff00) >> 8;
6307 b = (color & 0x000000ff) >> 0;
6309 switch(destfmt)
6311 case WINED3DFMT_R5G6B5:
6312 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6313 r = (r * 32) / 256;
6314 g = (g * 64) / 256;
6315 b = (b * 32) / 256;
6316 ret = r << 11;
6317 ret |= g << 5;
6318 ret |= b;
6319 TRACE("Returning %08x\n", ret);
6320 return ret;
6322 case WINED3DFMT_X1R5G5B5:
6323 case WINED3DFMT_A1R5G5B5:
6324 a = (a * 2) / 256;
6325 r = (r * 32) / 256;
6326 g = (g * 32) / 256;
6327 b = (b * 32) / 256;
6328 ret = a << 15;
6329 ret |= r << 10;
6330 ret |= g << 5;
6331 ret |= b << 0;
6332 TRACE("Returning %08x\n", ret);
6333 return ret;
6335 case WINED3DFMT_A8:
6336 TRACE("Returning %08x\n", a);
6337 return a;
6339 case WINED3DFMT_X4R4G4B4:
6340 case WINED3DFMT_A4R4G4B4:
6341 a = (a * 16) / 256;
6342 r = (r * 16) / 256;
6343 g = (g * 16) / 256;
6344 b = (b * 16) / 256;
6345 ret = a << 12;
6346 ret |= r << 8;
6347 ret |= g << 4;
6348 ret |= b << 0;
6349 TRACE("Returning %08x\n", ret);
6350 return ret;
6352 case WINED3DFMT_R3G3B2:
6353 r = (r * 8) / 256;
6354 g = (g * 8) / 256;
6355 b = (b * 4) / 256;
6356 ret = r << 5;
6357 ret |= g << 2;
6358 ret |= b << 0;
6359 TRACE("Returning %08x\n", ret);
6360 return ret;
6362 case WINED3DFMT_X8B8G8R8:
6363 case WINED3DFMT_A8B8G8R8:
6364 ret = a << 24;
6365 ret |= b << 16;
6366 ret |= g << 8;
6367 ret |= r << 0;
6368 TRACE("Returning %08x\n", ret);
6369 return ret;
6371 case WINED3DFMT_A2R10G10B10:
6372 a = (a * 4) / 256;
6373 r = (r * 1024) / 256;
6374 g = (g * 1024) / 256;
6375 b = (b * 1024) / 256;
6376 ret = a << 30;
6377 ret |= r << 20;
6378 ret |= g << 10;
6379 ret |= b << 0;
6380 TRACE("Returning %08x\n", ret);
6381 return ret;
6383 case WINED3DFMT_A2B10G10R10:
6384 a = (a * 4) / 256;
6385 r = (r * 1024) / 256;
6386 g = (g * 1024) / 256;
6387 b = (b * 1024) / 256;
6388 ret = a << 30;
6389 ret |= b << 20;
6390 ret |= g << 10;
6391 ret |= r << 0;
6392 TRACE("Returning %08x\n", ret);
6393 return ret;
6395 default:
6396 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6397 return 0;
6401 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6402 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6403 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6404 WINEDDBLTFX BltFx;
6405 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6407 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6408 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6409 return WINED3DERR_INVALIDCALL;
6412 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6413 color_fill_fbo(iface, pSurface, pRect, color);
6414 return WINED3D_OK;
6415 } else {
6416 /* Just forward this to the DirectDraw blitting engine */
6417 memset(&BltFx, 0, sizeof(BltFx));
6418 BltFx.dwSize = sizeof(BltFx);
6419 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6420 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6424 /* rendertarget and depth stencil functions */
6425 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6426 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6428 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6429 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6430 return WINED3DERR_INVALIDCALL;
6433 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6434 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6435 /* Note inc ref on returned surface */
6436 if(*ppRenderTarget != NULL)
6437 IWineD3DSurface_AddRef(*ppRenderTarget);
6438 return WINED3D_OK;
6441 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6443 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6444 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6445 IWineD3DSwapChainImpl *Swapchain;
6446 HRESULT hr;
6448 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6450 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6451 if(hr != WINED3D_OK) {
6452 ERR("Can't get the swapchain\n");
6453 return hr;
6456 /* Make sure to release the swapchain */
6457 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6459 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6460 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6461 return WINED3DERR_INVALIDCALL;
6463 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6464 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6465 return WINED3DERR_INVALIDCALL;
6468 if(Swapchain->frontBuffer != Front) {
6469 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6471 if(Swapchain->frontBuffer)
6472 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6473 Swapchain->frontBuffer = Front;
6475 if(Swapchain->frontBuffer) {
6476 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6480 if(Back && !Swapchain->backBuffer) {
6481 /* We need memory for the back buffer array - only one back buffer this way */
6482 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6483 if(!Swapchain->backBuffer) {
6484 ERR("Out of memory\n");
6485 return E_OUTOFMEMORY;
6489 if(Swapchain->backBuffer[0] != Back) {
6490 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6492 /* What to do about the context here in the case of multithreading? Not sure.
6493 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6495 ENTER_GL();
6496 if(!Swapchain->backBuffer[0]) {
6497 /* GL was told to draw to the front buffer at creation,
6498 * undo that
6500 glDrawBuffer(GL_BACK);
6501 checkGLcall("glDrawBuffer(GL_BACK)");
6502 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6503 Swapchain->presentParms.BackBufferCount = 1;
6504 } else if (!Back) {
6505 /* That makes problems - disable for now */
6506 /* glDrawBuffer(GL_FRONT); */
6507 checkGLcall("glDrawBuffer(GL_FRONT)");
6508 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6509 Swapchain->presentParms.BackBufferCount = 0;
6511 LEAVE_GL();
6513 if(Swapchain->backBuffer[0])
6514 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6515 Swapchain->backBuffer[0] = Back;
6517 if(Swapchain->backBuffer[0]) {
6518 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6519 } else {
6520 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6521 Swapchain->backBuffer = NULL;
6526 return WINED3D_OK;
6529 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6531 *ppZStencilSurface = This->stencilBufferTarget;
6532 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6534 if(*ppZStencilSurface != NULL) {
6535 /* Note inc ref on returned surface */
6536 IWineD3DSurface_AddRef(*ppZStencilSurface);
6537 return WINED3D_OK;
6538 } else {
6539 return WINED3DERR_NOTFOUND;
6543 /* TODO: Handle stencil attachments */
6544 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6547 TRACE("Set depth stencil to %p\n", depth_stencil);
6549 if (depth_stencil) {
6550 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6551 } else {
6552 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6553 checkGLcall("glFramebufferTexture2DEXT()");
6557 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6560 TRACE("Set render target %u to %p\n", idx, render_target);
6562 if (render_target) {
6563 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6564 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6565 } else {
6566 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6567 checkGLcall("glFramebufferTexture2DEXT()");
6569 This->draw_buffers[idx] = GL_NONE;
6573 static void check_fbo_status(IWineD3DDevice *iface) {
6574 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6575 GLenum status;
6577 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6578 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6579 TRACE("FBO complete\n");
6580 } else {
6581 IWineD3DSurfaceImpl *attachment;
6582 int i;
6583 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6585 /* Dump the FBO attachments */
6586 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6587 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
6588 if (attachment) {
6589 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6590 attachment->pow2Width, attachment->pow2Height);
6593 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
6594 if (attachment) {
6595 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6596 attachment->pow2Width, attachment->pow2Height);
6601 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6603 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6604 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6606 if (!ds_impl) return FALSE;
6608 if (ds_impl->current_renderbuffer) {
6609 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6610 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6613 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6614 rt_impl->pow2Height != ds_impl->pow2Height);
6617 void apply_fbo_state(IWineD3DDevice *iface) {
6618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6619 WineD3DContext *context = This->activeContext;
6620 unsigned int i;
6622 if (This->render_offscreen) {
6623 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
6625 /* Apply render targets */
6626 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6627 IWineD3DSurface *render_target = This->render_targets[i];
6628 if (context->fbo_color_attachments[i] != render_target) {
6629 set_render_target_fbo(iface, i, render_target);
6630 context->fbo_color_attachments[i] = render_target;
6634 /* Apply depth targets */
6635 if (context->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6636 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6637 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6639 if (This->stencilBufferTarget) {
6640 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6642 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6643 context->fbo_depth_attachment = This->stencilBufferTarget;
6645 } else {
6646 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6649 check_fbo_status(iface);
6652 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6653 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6654 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6655 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6656 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6657 GLenum gl_filter;
6658 POINT offset = {0, 0};
6660 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6661 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6662 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6663 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6665 switch (filter) {
6666 case WINED3DTEXF_LINEAR:
6667 gl_filter = GL_LINEAR;
6668 break;
6670 default:
6671 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6672 case WINED3DTEXF_NONE:
6673 case WINED3DTEXF_POINT:
6674 gl_filter = GL_NEAREST;
6675 break;
6678 /* Attach src surface to src fbo */
6679 src_swapchain = get_swapchain(src_surface);
6680 if (src_swapchain) {
6681 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6683 TRACE("Source surface %p is onscreen\n", src_surface);
6684 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6685 /* Make sure the drawable is up to date. In the offscreen case
6686 * attach_surface_fbo() implicitly takes care of this. */
6687 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6689 if(buffer == GL_FRONT) {
6690 RECT windowsize;
6691 UINT h;
6692 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6693 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6694 h = windowsize.bottom - windowsize.top;
6695 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6696 src_rect->y1 = offset.y + h - src_rect->y1;
6697 src_rect->y2 = offset.y + h - src_rect->y2;
6698 } else {
6699 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6700 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6703 ENTER_GL();
6704 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6705 glReadBuffer(buffer);
6706 checkGLcall("glReadBuffer()");
6707 } else {
6708 TRACE("Source surface %p is offscreen\n", src_surface);
6709 ENTER_GL();
6710 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6711 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6712 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6713 checkGLcall("glReadBuffer()");
6714 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6715 checkGLcall("glFramebufferRenderbufferEXT");
6717 LEAVE_GL();
6719 /* Attach dst surface to dst fbo */
6720 dst_swapchain = get_swapchain(dst_surface);
6721 if (dst_swapchain) {
6722 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6724 TRACE("Destination surface %p is onscreen\n", dst_surface);
6725 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6726 /* Make sure the drawable is up to date. In the offscreen case
6727 * attach_surface_fbo() implicitly takes care of this. */
6728 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6730 if(buffer == GL_FRONT) {
6731 RECT windowsize;
6732 UINT h;
6733 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6734 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6735 h = windowsize.bottom - windowsize.top;
6736 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6737 dst_rect->y1 = offset.y + h - dst_rect->y1;
6738 dst_rect->y2 = offset.y + h - dst_rect->y2;
6739 } else {
6740 /* Screen coords = window coords, surface height = window height */
6741 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6742 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6745 ENTER_GL();
6746 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6747 glDrawBuffer(buffer);
6748 checkGLcall("glDrawBuffer()");
6749 } else {
6750 TRACE("Destination surface %p is offscreen\n", dst_surface);
6752 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6753 if(!src_swapchain) {
6754 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6757 ENTER_GL();
6758 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6759 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6760 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6761 checkGLcall("glDrawBuffer()");
6762 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6763 checkGLcall("glFramebufferRenderbufferEXT");
6765 glDisable(GL_SCISSOR_TEST);
6766 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6768 if (flip) {
6769 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6770 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6771 checkGLcall("glBlitFramebuffer()");
6772 } else {
6773 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6774 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6775 checkGLcall("glBlitFramebuffer()");
6778 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6780 if (This->render_offscreen) {
6781 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6782 } else {
6783 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6784 checkGLcall("glBindFramebuffer()");
6787 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6788 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6789 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6790 glDrawBuffer(GL_BACK);
6791 checkGLcall("glDrawBuffer()");
6793 LEAVE_GL();
6796 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6797 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6798 WINED3DVIEWPORT viewport;
6800 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6802 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6803 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6804 This, RenderTargetIndex, GL_LIMITS(buffers));
6805 return WINED3DERR_INVALIDCALL;
6808 /* MSDN says that null disables the render target
6809 but a device must always be associated with a render target
6810 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6812 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6813 FIXME("Trying to set render target 0 to NULL\n");
6814 return WINED3DERR_INVALIDCALL;
6816 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6817 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);
6818 return WINED3DERR_INVALIDCALL;
6821 /* If we are trying to set what we already have, don't bother */
6822 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6823 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6824 return WINED3D_OK;
6826 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6827 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6828 This->render_targets[RenderTargetIndex] = pRenderTarget;
6830 /* Render target 0 is special */
6831 if(RenderTargetIndex == 0) {
6832 /* Finally, reset the viewport as the MSDN states. */
6833 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6834 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6835 viewport.X = 0;
6836 viewport.Y = 0;
6837 viewport.MaxZ = 1.0f;
6838 viewport.MinZ = 0.0f;
6839 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6840 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6841 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6843 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6845 return WINED3D_OK;
6848 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6849 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6850 HRESULT hr = WINED3D_OK;
6851 IWineD3DSurface *tmp;
6853 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6855 if (pNewZStencil == This->stencilBufferTarget) {
6856 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6857 } else {
6858 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6859 * depending on the renter target implementation being used.
6860 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6861 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6862 * stencil buffer and incur an extra memory overhead
6863 ******************************************************/
6865 if (This->stencilBufferTarget) {
6866 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6867 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6868 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6871 tmp = This->stencilBufferTarget;
6872 This->stencilBufferTarget = pNewZStencil;
6873 /* should we be calling the parent or the wined3d surface? */
6874 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6875 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6876 hr = WINED3D_OK;
6878 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6879 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6880 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6886 return hr;
6889 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6890 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6892 /* TODO: the use of Impl is deprecated. */
6893 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6894 WINED3DLOCKED_RECT lockedRect;
6896 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6898 /* some basic validation checks */
6899 if(This->cursorTexture) {
6900 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6901 ENTER_GL();
6902 glDeleteTextures(1, &This->cursorTexture);
6903 LEAVE_GL();
6904 This->cursorTexture = 0;
6907 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6908 This->haveHardwareCursor = TRUE;
6909 else
6910 This->haveHardwareCursor = FALSE;
6912 if(pCursorBitmap) {
6913 WINED3DLOCKED_RECT rect;
6915 /* MSDN: Cursor must be A8R8G8B8 */
6916 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6917 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6918 return WINED3DERR_INVALIDCALL;
6921 /* MSDN: Cursor must be smaller than the display mode */
6922 if(pSur->currentDesc.Width > This->ddraw_width ||
6923 pSur->currentDesc.Height > This->ddraw_height) {
6924 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);
6925 return WINED3DERR_INVALIDCALL;
6928 if (!This->haveHardwareCursor) {
6929 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6931 /* Do not store the surface's pointer because the application may
6932 * release it after setting the cursor image. Windows doesn't
6933 * addref the set surface, so we can't do this either without
6934 * creating circular refcount dependencies. Copy out the gl texture
6935 * instead.
6937 This->cursorWidth = pSur->currentDesc.Width;
6938 This->cursorHeight = pSur->currentDesc.Height;
6939 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6941 const GlPixelFormatDesc *glDesc;
6942 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6943 char *mem, *bits = (char *)rect.pBits;
6944 GLint intfmt = glDesc->glInternal;
6945 GLint format = glDesc->glFormat;
6946 GLint type = glDesc->glType;
6947 INT height = This->cursorHeight;
6948 INT width = This->cursorWidth;
6949 INT bpp = tableEntry->bpp;
6950 INT i, sampler;
6952 /* Reformat the texture memory (pitch and width can be
6953 * different) */
6954 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6955 for(i = 0; i < height; i++)
6956 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6957 IWineD3DSurface_UnlockRect(pCursorBitmap);
6958 ENTER_GL();
6960 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6961 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6962 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6965 /* Make sure that a proper texture unit is selected */
6966 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6967 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6968 checkGLcall("glActiveTextureARB");
6970 sampler = This->rev_tex_unit_map[0];
6971 if (sampler != -1) {
6972 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6974 /* Create a new cursor texture */
6975 glGenTextures(1, &This->cursorTexture);
6976 checkGLcall("glGenTextures");
6977 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6978 checkGLcall("glBindTexture");
6979 /* Copy the bitmap memory into the cursor texture */
6980 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6981 HeapFree(GetProcessHeap(), 0, mem);
6982 checkGLcall("glTexImage2D");
6984 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6985 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6986 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6989 LEAVE_GL();
6991 else
6993 FIXME("A cursor texture was not returned.\n");
6994 This->cursorTexture = 0;
6997 else
6999 /* Draw a hardware cursor */
7000 ICONINFO cursorInfo;
7001 HCURSOR cursor;
7002 /* Create and clear maskBits because it is not needed for
7003 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7004 * chunks. */
7005 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7006 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7007 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7008 WINED3DLOCK_NO_DIRTY_UPDATE |
7009 WINED3DLOCK_READONLY
7011 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7012 pSur->currentDesc.Height);
7014 cursorInfo.fIcon = FALSE;
7015 cursorInfo.xHotspot = XHotSpot;
7016 cursorInfo.yHotspot = YHotSpot;
7017 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7018 pSur->currentDesc.Height, 1,
7019 1, &maskBits);
7020 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7021 pSur->currentDesc.Height, 1,
7022 32, lockedRect.pBits);
7023 IWineD3DSurface_UnlockRect(pCursorBitmap);
7024 /* Create our cursor and clean up. */
7025 cursor = CreateIconIndirect(&cursorInfo);
7026 SetCursor(cursor);
7027 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7028 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7029 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7030 This->hardwareCursor = cursor;
7031 HeapFree(GetProcessHeap(), 0, maskBits);
7035 This->xHotSpot = XHotSpot;
7036 This->yHotSpot = YHotSpot;
7037 return WINED3D_OK;
7040 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7042 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7044 This->xScreenSpace = XScreenSpace;
7045 This->yScreenSpace = YScreenSpace;
7047 return;
7051 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7052 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7053 BOOL oldVisible = This->bCursorVisible;
7054 POINT pt;
7056 TRACE("(%p) : visible(%d)\n", This, bShow);
7059 * When ShowCursor is first called it should make the cursor appear at the OS's last
7060 * known cursor position. Because of this, some applications just repetitively call
7061 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7063 GetCursorPos(&pt);
7064 This->xScreenSpace = pt.x;
7065 This->yScreenSpace = pt.y;
7067 if (This->haveHardwareCursor) {
7068 This->bCursorVisible = bShow;
7069 if (bShow)
7070 SetCursor(This->hardwareCursor);
7071 else
7072 SetCursor(NULL);
7074 else
7076 if (This->cursorTexture)
7077 This->bCursorVisible = bShow;
7080 return oldVisible;
7083 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7085 IWineD3DResourceImpl *resource;
7086 TRACE("(%p) : state (%u)\n", This, This->state);
7088 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7089 switch (This->state) {
7090 case WINED3D_OK:
7091 return WINED3D_OK;
7092 case WINED3DERR_DEVICELOST:
7094 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7095 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7096 return WINED3DERR_DEVICENOTRESET;
7098 return WINED3DERR_DEVICELOST;
7100 case WINED3DERR_DRIVERINTERNALERROR:
7101 return WINED3DERR_DRIVERINTERNALERROR;
7104 /* Unknown state */
7105 return WINED3DERR_DRIVERINTERNALERROR;
7109 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7110 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7111 /** FIXME: Resource tracking needs to be done,
7112 * The closes we can do to this is set the priorities of all managed textures low
7113 * and then reset them.
7114 ***********************************************************/
7115 FIXME("(%p) : stub\n", This);
7116 return WINED3D_OK;
7119 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7120 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7122 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7123 if(surface->Flags & SFLAG_DIBSECTION) {
7124 /* Release the DC */
7125 SelectObject(surface->hDC, surface->dib.holdbitmap);
7126 DeleteDC(surface->hDC);
7127 /* Release the DIB section */
7128 DeleteObject(surface->dib.DIBsection);
7129 surface->dib.bitmap_data = NULL;
7130 surface->resource.allocatedMemory = NULL;
7131 surface->Flags &= ~SFLAG_DIBSECTION;
7133 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7134 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7135 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7136 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7137 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7138 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7139 } else {
7140 surface->pow2Width = surface->pow2Height = 1;
7141 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7142 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7144 surface->glRect.left = 0;
7145 surface->glRect.top = 0;
7146 surface->glRect.right = surface->pow2Width;
7147 surface->glRect.bottom = surface->pow2Height;
7149 if(surface->glDescription.textureName) {
7150 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7151 ENTER_GL();
7152 glDeleteTextures(1, &surface->glDescription.textureName);
7153 LEAVE_GL();
7154 surface->glDescription.textureName = 0;
7155 surface->Flags &= ~SFLAG_CLIENT;
7157 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7158 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7159 surface->Flags |= SFLAG_NONPOW2;
7160 } else {
7161 surface->Flags &= ~SFLAG_NONPOW2;
7163 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7164 surface->resource.allocatedMemory = NULL;
7165 surface->resource.heapMemory = NULL;
7166 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7167 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7168 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7169 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7170 } else {
7171 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7175 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7176 TRACE("Unloading resource %p\n", resource);
7177 IWineD3DResource_UnLoad(resource);
7178 IWineD3DResource_Release(resource);
7179 return S_OK;
7182 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7183 UINT i, count;
7184 WINED3DDISPLAYMODE m;
7185 HRESULT hr;
7187 /* All Windowed modes are supported, as is leaving the current mode */
7188 if(pp->Windowed) return TRUE;
7189 if(!pp->BackBufferWidth) return TRUE;
7190 if(!pp->BackBufferHeight) return TRUE;
7192 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7193 for(i = 0; i < count; i++) {
7194 memset(&m, 0, sizeof(m));
7195 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7196 if(FAILED(hr)) {
7197 ERR("EnumAdapterModes failed\n");
7199 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7200 /* Mode found, it is supported */
7201 return TRUE;
7204 /* Mode not found -> not supported */
7205 return FALSE;
7208 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7210 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7211 UINT i;
7212 IWineD3DBaseShaderImpl *shader;
7214 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7215 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7216 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7219 ENTER_GL();
7220 if(This->depth_blt_texture) {
7221 glDeleteTextures(1, &This->depth_blt_texture);
7222 This->depth_blt_texture = 0;
7224 if (This->depth_blt_rb) {
7225 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7226 This->depth_blt_rb = 0;
7227 This->depth_blt_rb_w = 0;
7228 This->depth_blt_rb_h = 0;
7230 This->blitter->free_private(iface);
7231 This->frag_pipe->free_private(iface);
7232 This->shader_backend->shader_free_private(iface);
7234 for (i = 0; i < GL_LIMITS(textures); i++) {
7235 /* Textures are recreated below */
7236 glDeleteTextures(1, &This->dummyTextureName[i]);
7237 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7238 This->dummyTextureName[i] = 0;
7240 LEAVE_GL();
7242 while(This->numContexts) {
7243 DestroyContext(This, This->contexts[0]);
7245 This->activeContext = NULL;
7246 HeapFree(GetProcessHeap(), 0, swapchain->context);
7247 swapchain->context = NULL;
7248 swapchain->num_contexts = 0;
7251 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7253 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7254 HRESULT hr;
7255 IWineD3DSurfaceImpl *target;
7257 /* Recreate the primary swapchain's context */
7258 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7259 if(swapchain->backBuffer) {
7260 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7261 } else {
7262 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7264 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7265 &swapchain->presentParms);
7266 swapchain->num_contexts = 1;
7267 This->activeContext = swapchain->context[0];
7269 create_dummy_textures(This);
7271 hr = This->shader_backend->shader_alloc_private(iface);
7272 if(FAILED(hr)) {
7273 ERR("Failed to recreate shader private data\n");
7274 goto err_out;
7276 hr = This->frag_pipe->alloc_private(iface);
7277 if(FAILED(hr)) {
7278 TRACE("Fragment pipeline private data couldn't be allocated\n");
7279 goto err_out;
7281 hr = This->blitter->alloc_private(iface);
7282 if(FAILED(hr)) {
7283 TRACE("Blitter private data couldn't be allocated\n");
7284 goto err_out;
7287 return WINED3D_OK;
7289 err_out:
7290 This->blitter->free_private(iface);
7291 This->frag_pipe->free_private(iface);
7292 This->shader_backend->shader_free_private(iface);
7293 return hr;
7296 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7298 IWineD3DSwapChainImpl *swapchain;
7299 HRESULT hr;
7300 BOOL DisplayModeChanged = FALSE;
7301 WINED3DDISPLAYMODE mode;
7302 TRACE("(%p)\n", This);
7304 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7305 if(FAILED(hr)) {
7306 ERR("Failed to get the first implicit swapchain\n");
7307 return hr;
7310 if(!is_display_mode_supported(This, pPresentationParameters)) {
7311 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7312 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7313 pPresentationParameters->BackBufferHeight);
7314 return WINED3DERR_INVALIDCALL;
7317 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7318 * on an existing gl context, so there's no real need for recreation.
7320 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7322 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7324 TRACE("New params:\n");
7325 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7326 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7327 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7328 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7329 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7330 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7331 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7332 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7333 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7334 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7335 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7336 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7337 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7339 /* No special treatment of these parameters. Just store them */
7340 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7341 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7342 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7343 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7345 /* What to do about these? */
7346 if(pPresentationParameters->BackBufferCount != 0 &&
7347 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7348 ERR("Cannot change the back buffer count yet\n");
7350 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7351 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7352 ERR("Cannot change the back buffer format yet\n");
7354 if(pPresentationParameters->hDeviceWindow != NULL &&
7355 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7356 ERR("Cannot change the device window yet\n");
7358 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7359 ERR("What do do about a changed auto depth stencil parameter?\n");
7362 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7364 if(pPresentationParameters->Windowed) {
7365 mode.Width = swapchain->orig_width;
7366 mode.Height = swapchain->orig_height;
7367 mode.RefreshRate = 0;
7368 mode.Format = swapchain->presentParms.BackBufferFormat;
7369 } else {
7370 mode.Width = pPresentationParameters->BackBufferWidth;
7371 mode.Height = pPresentationParameters->BackBufferHeight;
7372 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7373 mode.Format = swapchain->presentParms.BackBufferFormat;
7376 /* Should Width == 800 && Height == 0 set 800x600? */
7377 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7378 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7379 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7381 WINED3DVIEWPORT vp;
7382 int i;
7384 vp.X = 0;
7385 vp.Y = 0;
7386 vp.Width = pPresentationParameters->BackBufferWidth;
7387 vp.Height = pPresentationParameters->BackBufferHeight;
7388 vp.MinZ = 0;
7389 vp.MaxZ = 1;
7391 if(!pPresentationParameters->Windowed) {
7392 DisplayModeChanged = TRUE;
7394 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7395 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7397 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7398 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7399 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7401 if(This->auto_depth_stencil_buffer) {
7402 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7406 /* Now set the new viewport */
7407 IWineD3DDevice_SetViewport(iface, &vp);
7410 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7411 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7412 DisplayModeChanged) {
7414 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7416 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7417 if(swapchain->presentParms.Windowed) {
7418 /* switch from windowed to fs */
7419 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7420 pPresentationParameters->BackBufferWidth,
7421 pPresentationParameters->BackBufferHeight);
7422 } else {
7423 /* Fullscreen -> fullscreen mode change */
7424 MoveWindow(swapchain->win_handle, 0, 0,
7425 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7426 TRUE);
7428 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7429 /* Fullscreen -> windowed switch */
7430 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7432 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7433 } else if(!pPresentationParameters->Windowed) {
7434 DWORD style = This->style, exStyle = This->exStyle;
7435 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7436 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7437 * Reset to clear up their mess. Guild Wars also loses the device during that.
7439 This->style = 0;
7440 This->exStyle = 0;
7441 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7442 pPresentationParameters->BackBufferWidth,
7443 pPresentationParameters->BackBufferHeight);
7444 This->style = style;
7445 This->exStyle = exStyle;
7448 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7449 if(FAILED(hr)) {
7450 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7453 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7454 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7456 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7457 * first use
7459 return hr;
7462 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7464 /** FIXME: always true at the moment **/
7465 if(!bEnableDialogs) {
7466 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7468 return WINED3D_OK;
7472 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7474 TRACE("(%p) : pParameters %p\n", This, pParameters);
7476 *pParameters = This->createParms;
7477 return WINED3D_OK;
7480 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7481 IWineD3DSwapChain *swapchain;
7483 TRACE("Relaying to swapchain\n");
7485 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7486 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7487 IWineD3DSwapChain_Release(swapchain);
7489 return;
7492 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7493 IWineD3DSwapChain *swapchain;
7495 TRACE("Relaying to swapchain\n");
7497 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7498 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7499 IWineD3DSwapChain_Release(swapchain);
7501 return;
7505 /** ********************************************************
7506 * Notification functions
7507 ** ********************************************************/
7508 /** This function must be called in the release of a resource when ref == 0,
7509 * the contents of resource must still be correct,
7510 * any handles to other resource held by the caller must be closed
7511 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7512 *****************************************************/
7513 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7516 TRACE("(%p) : Adding Resource %p\n", This, resource);
7517 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7520 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7523 TRACE("(%p) : Removing resource %p\n", This, resource);
7525 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7529 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7531 int counter;
7533 TRACE("(%p) : resource %p\n", This, resource);
7534 switch(IWineD3DResource_GetType(resource)){
7535 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7536 case WINED3DRTYPE_SURFACE: {
7537 unsigned int i;
7539 /* Cleanup any FBO attachments if d3d is enabled */
7540 if(This->d3d_initialized) {
7541 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7542 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7544 TRACE("Last active render target destroyed\n");
7545 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7546 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7547 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7548 * and the lastActiveRenderTarget member shouldn't matter
7550 if(swapchain) {
7551 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7552 TRACE("Activating primary back buffer\n");
7553 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7554 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7555 /* Single buffering environment */
7556 TRACE("Activating primary front buffer\n");
7557 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7558 } else {
7559 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7560 /* Implicit render target destroyed, that means the device is being destroyed
7561 * whatever we set here, it shouldn't matter
7563 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7565 } else {
7566 /* May happen during ddraw uninitialization */
7567 TRACE("Render target set, but swapchain does not exist!\n");
7568 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7572 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7573 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7574 This->render_targets[i] = NULL;
7577 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7578 This->stencilBufferTarget = NULL;
7581 for (i = 0; i < This->numContexts; ++i) {
7582 int j;
7583 for (j = 0; j < GL_LIMITS(buffers); ++j) {
7584 if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
7585 This->contexts[i]->fbo_color_attachments[j] = NULL;
7588 if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7589 This->contexts[i]->fbo_depth_attachment = NULL;
7594 break;
7596 case WINED3DRTYPE_TEXTURE:
7597 case WINED3DRTYPE_CUBETEXTURE:
7598 case WINED3DRTYPE_VOLUMETEXTURE:
7599 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7600 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7601 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7602 This->stateBlock->textures[counter] = NULL;
7604 if (This->updateStateBlock != This->stateBlock ){
7605 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7606 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7607 This->updateStateBlock->textures[counter] = NULL;
7611 break;
7612 case WINED3DRTYPE_VOLUME:
7613 /* TODO: nothing really? */
7614 break;
7615 case WINED3DRTYPE_VERTEXBUFFER:
7616 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7618 int streamNumber;
7619 TRACE("Cleaning up stream pointers\n");
7621 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7622 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7623 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7625 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7626 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7627 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7628 This->updateStateBlock->streamSource[streamNumber] = 0;
7629 /* Set changed flag? */
7632 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) */
7633 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7634 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7635 This->stateBlock->streamSource[streamNumber] = 0;
7640 break;
7641 case WINED3DRTYPE_INDEXBUFFER:
7642 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7643 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7644 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7645 This->updateStateBlock->pIndexData = NULL;
7648 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7649 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7650 This->stateBlock->pIndexData = NULL;
7654 break;
7655 default:
7656 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7657 break;
7661 /* Remove the resource from the resourceStore */
7662 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7664 TRACE("Resource released\n");
7668 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7670 IWineD3DResourceImpl *resource, *cursor;
7671 HRESULT ret;
7672 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7674 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7675 TRACE("enumerating resource %p\n", resource);
7676 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7677 ret = pCallback((IWineD3DResource *) resource, pData);
7678 if(ret == S_FALSE) {
7679 TRACE("Canceling enumeration\n");
7680 break;
7683 return WINED3D_OK;
7686 /**********************************************************
7687 * IWineD3DDevice VTbl follows
7688 **********************************************************/
7690 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7692 /*** IUnknown methods ***/
7693 IWineD3DDeviceImpl_QueryInterface,
7694 IWineD3DDeviceImpl_AddRef,
7695 IWineD3DDeviceImpl_Release,
7696 /*** IWineD3DDevice methods ***/
7697 IWineD3DDeviceImpl_GetParent,
7698 /*** Creation methods**/
7699 IWineD3DDeviceImpl_CreateVertexBuffer,
7700 IWineD3DDeviceImpl_CreateIndexBuffer,
7701 IWineD3DDeviceImpl_CreateStateBlock,
7702 IWineD3DDeviceImpl_CreateSurface,
7703 IWineD3DDeviceImpl_CreateTexture,
7704 IWineD3DDeviceImpl_CreateVolumeTexture,
7705 IWineD3DDeviceImpl_CreateVolume,
7706 IWineD3DDeviceImpl_CreateCubeTexture,
7707 IWineD3DDeviceImpl_CreateQuery,
7708 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7709 IWineD3DDeviceImpl_CreateVertexDeclaration,
7710 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7711 IWineD3DDeviceImpl_CreateVertexShader,
7712 IWineD3DDeviceImpl_CreatePixelShader,
7713 IWineD3DDeviceImpl_CreatePalette,
7714 /*** Odd functions **/
7715 IWineD3DDeviceImpl_Init3D,
7716 IWineD3DDeviceImpl_InitGDI,
7717 IWineD3DDeviceImpl_Uninit3D,
7718 IWineD3DDeviceImpl_UninitGDI,
7719 IWineD3DDeviceImpl_SetMultithreaded,
7720 IWineD3DDeviceImpl_EvictManagedResources,
7721 IWineD3DDeviceImpl_GetAvailableTextureMem,
7722 IWineD3DDeviceImpl_GetBackBuffer,
7723 IWineD3DDeviceImpl_GetCreationParameters,
7724 IWineD3DDeviceImpl_GetDeviceCaps,
7725 IWineD3DDeviceImpl_GetDirect3D,
7726 IWineD3DDeviceImpl_GetDisplayMode,
7727 IWineD3DDeviceImpl_SetDisplayMode,
7728 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7729 IWineD3DDeviceImpl_GetRasterStatus,
7730 IWineD3DDeviceImpl_GetSwapChain,
7731 IWineD3DDeviceImpl_Reset,
7732 IWineD3DDeviceImpl_SetDialogBoxMode,
7733 IWineD3DDeviceImpl_SetCursorProperties,
7734 IWineD3DDeviceImpl_SetCursorPosition,
7735 IWineD3DDeviceImpl_ShowCursor,
7736 IWineD3DDeviceImpl_TestCooperativeLevel,
7737 /*** Getters and setters **/
7738 IWineD3DDeviceImpl_SetClipPlane,
7739 IWineD3DDeviceImpl_GetClipPlane,
7740 IWineD3DDeviceImpl_SetClipStatus,
7741 IWineD3DDeviceImpl_GetClipStatus,
7742 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7743 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7744 IWineD3DDeviceImpl_SetDepthStencilSurface,
7745 IWineD3DDeviceImpl_GetDepthStencilSurface,
7746 IWineD3DDeviceImpl_SetFVF,
7747 IWineD3DDeviceImpl_GetFVF,
7748 IWineD3DDeviceImpl_SetGammaRamp,
7749 IWineD3DDeviceImpl_GetGammaRamp,
7750 IWineD3DDeviceImpl_SetIndices,
7751 IWineD3DDeviceImpl_GetIndices,
7752 IWineD3DDeviceImpl_SetBaseVertexIndex,
7753 IWineD3DDeviceImpl_GetBaseVertexIndex,
7754 IWineD3DDeviceImpl_SetLight,
7755 IWineD3DDeviceImpl_GetLight,
7756 IWineD3DDeviceImpl_SetLightEnable,
7757 IWineD3DDeviceImpl_GetLightEnable,
7758 IWineD3DDeviceImpl_SetMaterial,
7759 IWineD3DDeviceImpl_GetMaterial,
7760 IWineD3DDeviceImpl_SetNPatchMode,
7761 IWineD3DDeviceImpl_GetNPatchMode,
7762 IWineD3DDeviceImpl_SetPaletteEntries,
7763 IWineD3DDeviceImpl_GetPaletteEntries,
7764 IWineD3DDeviceImpl_SetPixelShader,
7765 IWineD3DDeviceImpl_GetPixelShader,
7766 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7767 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7768 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7769 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7770 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7771 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7772 IWineD3DDeviceImpl_SetRenderState,
7773 IWineD3DDeviceImpl_GetRenderState,
7774 IWineD3DDeviceImpl_SetRenderTarget,
7775 IWineD3DDeviceImpl_GetRenderTarget,
7776 IWineD3DDeviceImpl_SetFrontBackBuffers,
7777 IWineD3DDeviceImpl_SetSamplerState,
7778 IWineD3DDeviceImpl_GetSamplerState,
7779 IWineD3DDeviceImpl_SetScissorRect,
7780 IWineD3DDeviceImpl_GetScissorRect,
7781 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7782 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7783 IWineD3DDeviceImpl_SetStreamSource,
7784 IWineD3DDeviceImpl_GetStreamSource,
7785 IWineD3DDeviceImpl_SetStreamSourceFreq,
7786 IWineD3DDeviceImpl_GetStreamSourceFreq,
7787 IWineD3DDeviceImpl_SetTexture,
7788 IWineD3DDeviceImpl_GetTexture,
7789 IWineD3DDeviceImpl_SetTextureStageState,
7790 IWineD3DDeviceImpl_GetTextureStageState,
7791 IWineD3DDeviceImpl_SetTransform,
7792 IWineD3DDeviceImpl_GetTransform,
7793 IWineD3DDeviceImpl_SetVertexDeclaration,
7794 IWineD3DDeviceImpl_GetVertexDeclaration,
7795 IWineD3DDeviceImpl_SetVertexShader,
7796 IWineD3DDeviceImpl_GetVertexShader,
7797 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7798 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7799 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7800 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7801 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7802 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7803 IWineD3DDeviceImpl_SetViewport,
7804 IWineD3DDeviceImpl_GetViewport,
7805 IWineD3DDeviceImpl_MultiplyTransform,
7806 IWineD3DDeviceImpl_ValidateDevice,
7807 IWineD3DDeviceImpl_ProcessVertices,
7808 /*** State block ***/
7809 IWineD3DDeviceImpl_BeginStateBlock,
7810 IWineD3DDeviceImpl_EndStateBlock,
7811 /*** Scene management ***/
7812 IWineD3DDeviceImpl_BeginScene,
7813 IWineD3DDeviceImpl_EndScene,
7814 IWineD3DDeviceImpl_Present,
7815 IWineD3DDeviceImpl_Clear,
7816 /*** Drawing ***/
7817 IWineD3DDeviceImpl_DrawPrimitive,
7818 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7819 IWineD3DDeviceImpl_DrawPrimitiveUP,
7820 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7821 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7822 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7823 IWineD3DDeviceImpl_DrawRectPatch,
7824 IWineD3DDeviceImpl_DrawTriPatch,
7825 IWineD3DDeviceImpl_DeletePatch,
7826 IWineD3DDeviceImpl_ColorFill,
7827 IWineD3DDeviceImpl_UpdateTexture,
7828 IWineD3DDeviceImpl_UpdateSurface,
7829 IWineD3DDeviceImpl_GetFrontBufferData,
7830 /*** object tracking ***/
7831 IWineD3DDeviceImpl_ResourceReleased,
7832 IWineD3DDeviceImpl_EnumResources
7835 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7837 /*** IUnknown methods ***/
7838 IWineD3DDeviceImpl_QueryInterface,
7839 IWineD3DDeviceImpl_AddRef,
7840 IWineD3DDeviceImpl_Release,
7841 /*** IWineD3DDevice methods ***/
7842 IWineD3DDeviceImpl_GetParent,
7843 /*** Creation methods**/
7844 IWineD3DDeviceImpl_CreateVertexBuffer,
7845 IWineD3DDeviceImpl_CreateIndexBuffer,
7846 IWineD3DDeviceImpl_CreateStateBlock,
7847 IWineD3DDeviceImpl_CreateSurface,
7848 IWineD3DDeviceImpl_CreateTexture,
7849 IWineD3DDeviceImpl_CreateVolumeTexture,
7850 IWineD3DDeviceImpl_CreateVolume,
7851 IWineD3DDeviceImpl_CreateCubeTexture,
7852 IWineD3DDeviceImpl_CreateQuery,
7853 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7854 IWineD3DDeviceImpl_CreateVertexDeclaration,
7855 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7856 IWineD3DDeviceImpl_CreateVertexShader,
7857 IWineD3DDeviceImpl_CreatePixelShader,
7858 IWineD3DDeviceImpl_CreatePalette,
7859 /*** Odd functions **/
7860 IWineD3DDeviceImpl_Init3D,
7861 IWineD3DDeviceImpl_InitGDI,
7862 IWineD3DDeviceImpl_Uninit3D,
7863 IWineD3DDeviceImpl_UninitGDI,
7864 IWineD3DDeviceImpl_SetMultithreaded,
7865 IWineD3DDeviceImpl_EvictManagedResources,
7866 IWineD3DDeviceImpl_GetAvailableTextureMem,
7867 IWineD3DDeviceImpl_GetBackBuffer,
7868 IWineD3DDeviceImpl_GetCreationParameters,
7869 IWineD3DDeviceImpl_GetDeviceCaps,
7870 IWineD3DDeviceImpl_GetDirect3D,
7871 IWineD3DDeviceImpl_GetDisplayMode,
7872 IWineD3DDeviceImpl_SetDisplayMode,
7873 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7874 IWineD3DDeviceImpl_GetRasterStatus,
7875 IWineD3DDeviceImpl_GetSwapChain,
7876 IWineD3DDeviceImpl_Reset,
7877 IWineD3DDeviceImpl_SetDialogBoxMode,
7878 IWineD3DDeviceImpl_SetCursorProperties,
7879 IWineD3DDeviceImpl_SetCursorPosition,
7880 IWineD3DDeviceImpl_ShowCursor,
7881 IWineD3DDeviceImpl_TestCooperativeLevel,
7882 /*** Getters and setters **/
7883 IWineD3DDeviceImpl_SetClipPlane,
7884 IWineD3DDeviceImpl_GetClipPlane,
7885 IWineD3DDeviceImpl_SetClipStatus,
7886 IWineD3DDeviceImpl_GetClipStatus,
7887 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7888 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7889 IWineD3DDeviceImpl_SetDepthStencilSurface,
7890 IWineD3DDeviceImpl_GetDepthStencilSurface,
7891 IWineD3DDeviceImpl_SetFVF,
7892 IWineD3DDeviceImpl_GetFVF,
7893 IWineD3DDeviceImpl_SetGammaRamp,
7894 IWineD3DDeviceImpl_GetGammaRamp,
7895 IWineD3DDeviceImpl_SetIndices,
7896 IWineD3DDeviceImpl_GetIndices,
7897 IWineD3DDeviceImpl_SetBaseVertexIndex,
7898 IWineD3DDeviceImpl_GetBaseVertexIndex,
7899 IWineD3DDeviceImpl_SetLight,
7900 IWineD3DDeviceImpl_GetLight,
7901 IWineD3DDeviceImpl_SetLightEnable,
7902 IWineD3DDeviceImpl_GetLightEnable,
7903 IWineD3DDeviceImpl_SetMaterial,
7904 IWineD3DDeviceImpl_GetMaterial,
7905 IWineD3DDeviceImpl_SetNPatchMode,
7906 IWineD3DDeviceImpl_GetNPatchMode,
7907 IWineD3DDeviceImpl_SetPaletteEntries,
7908 IWineD3DDeviceImpl_GetPaletteEntries,
7909 IWineD3DDeviceImpl_SetPixelShader,
7910 IWineD3DDeviceImpl_GetPixelShader,
7911 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7912 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7913 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7914 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7915 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7916 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7917 IWineD3DDeviceImpl_SetRenderState,
7918 IWineD3DDeviceImpl_GetRenderState,
7919 IWineD3DDeviceImpl_SetRenderTarget,
7920 IWineD3DDeviceImpl_GetRenderTarget,
7921 IWineD3DDeviceImpl_SetFrontBackBuffers,
7922 IWineD3DDeviceImpl_SetSamplerState,
7923 IWineD3DDeviceImpl_GetSamplerState,
7924 IWineD3DDeviceImpl_SetScissorRect,
7925 IWineD3DDeviceImpl_GetScissorRect,
7926 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7927 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7928 IWineD3DDeviceImpl_SetStreamSource,
7929 IWineD3DDeviceImpl_GetStreamSource,
7930 IWineD3DDeviceImpl_SetStreamSourceFreq,
7931 IWineD3DDeviceImpl_GetStreamSourceFreq,
7932 IWineD3DDeviceImpl_SetTexture,
7933 IWineD3DDeviceImpl_GetTexture,
7934 IWineD3DDeviceImpl_SetTextureStageState,
7935 IWineD3DDeviceImpl_GetTextureStageState,
7936 IWineD3DDeviceImpl_SetTransform,
7937 IWineD3DDeviceImpl_GetTransform,
7938 IWineD3DDeviceImpl_SetVertexDeclaration,
7939 IWineD3DDeviceImpl_GetVertexDeclaration,
7940 IWineD3DDeviceImpl_SetVertexShader,
7941 IWineD3DDeviceImpl_GetVertexShader,
7942 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7943 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7944 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7945 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7946 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7947 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7948 IWineD3DDeviceImpl_SetViewport,
7949 IWineD3DDeviceImpl_GetViewport,
7950 IWineD3DDeviceImpl_MultiplyTransform,
7951 IWineD3DDeviceImpl_ValidateDevice,
7952 IWineD3DDeviceImpl_ProcessVertices,
7953 /*** State block ***/
7954 IWineD3DDeviceImpl_BeginStateBlock,
7955 IWineD3DDeviceImpl_EndStateBlock,
7956 /*** Scene management ***/
7957 IWineD3DDeviceImpl_BeginScene,
7958 IWineD3DDeviceImpl_EndScene,
7959 IWineD3DDeviceImpl_Present,
7960 IWineD3DDeviceImpl_Clear,
7961 /*** Drawing ***/
7962 IWineD3DDeviceImpl_DrawPrimitive,
7963 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7964 IWineD3DDeviceImpl_DrawPrimitiveUP,
7965 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7966 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7967 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7968 IWineD3DDeviceImpl_DrawRectPatch,
7969 IWineD3DDeviceImpl_DrawTriPatch,
7970 IWineD3DDeviceImpl_DeletePatch,
7971 IWineD3DDeviceImpl_ColorFill,
7972 IWineD3DDeviceImpl_UpdateTexture,
7973 IWineD3DDeviceImpl_UpdateSurface,
7974 IWineD3DDeviceImpl_GetFrontBufferData,
7975 /*** object tracking ***/
7976 IWineD3DDeviceImpl_ResourceReleased,
7977 IWineD3DDeviceImpl_EnumResources
7980 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7981 WINED3DRS_ALPHABLENDENABLE ,
7982 WINED3DRS_ALPHAFUNC ,
7983 WINED3DRS_ALPHAREF ,
7984 WINED3DRS_ALPHATESTENABLE ,
7985 WINED3DRS_BLENDOP ,
7986 WINED3DRS_COLORWRITEENABLE ,
7987 WINED3DRS_DESTBLEND ,
7988 WINED3DRS_DITHERENABLE ,
7989 WINED3DRS_FILLMODE ,
7990 WINED3DRS_FOGDENSITY ,
7991 WINED3DRS_FOGEND ,
7992 WINED3DRS_FOGSTART ,
7993 WINED3DRS_LASTPIXEL ,
7994 WINED3DRS_SHADEMODE ,
7995 WINED3DRS_SRCBLEND ,
7996 WINED3DRS_STENCILENABLE ,
7997 WINED3DRS_STENCILFAIL ,
7998 WINED3DRS_STENCILFUNC ,
7999 WINED3DRS_STENCILMASK ,
8000 WINED3DRS_STENCILPASS ,
8001 WINED3DRS_STENCILREF ,
8002 WINED3DRS_STENCILWRITEMASK ,
8003 WINED3DRS_STENCILZFAIL ,
8004 WINED3DRS_TEXTUREFACTOR ,
8005 WINED3DRS_WRAP0 ,
8006 WINED3DRS_WRAP1 ,
8007 WINED3DRS_WRAP2 ,
8008 WINED3DRS_WRAP3 ,
8009 WINED3DRS_WRAP4 ,
8010 WINED3DRS_WRAP5 ,
8011 WINED3DRS_WRAP6 ,
8012 WINED3DRS_WRAP7 ,
8013 WINED3DRS_ZENABLE ,
8014 WINED3DRS_ZFUNC ,
8015 WINED3DRS_ZWRITEENABLE
8018 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8019 WINED3DTSS_ADDRESSW ,
8020 WINED3DTSS_ALPHAARG0 ,
8021 WINED3DTSS_ALPHAARG1 ,
8022 WINED3DTSS_ALPHAARG2 ,
8023 WINED3DTSS_ALPHAOP ,
8024 WINED3DTSS_BUMPENVLOFFSET ,
8025 WINED3DTSS_BUMPENVLSCALE ,
8026 WINED3DTSS_BUMPENVMAT00 ,
8027 WINED3DTSS_BUMPENVMAT01 ,
8028 WINED3DTSS_BUMPENVMAT10 ,
8029 WINED3DTSS_BUMPENVMAT11 ,
8030 WINED3DTSS_COLORARG0 ,
8031 WINED3DTSS_COLORARG1 ,
8032 WINED3DTSS_COLORARG2 ,
8033 WINED3DTSS_COLOROP ,
8034 WINED3DTSS_RESULTARG ,
8035 WINED3DTSS_TEXCOORDINDEX ,
8036 WINED3DTSS_TEXTURETRANSFORMFLAGS
8039 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8040 WINED3DSAMP_ADDRESSU ,
8041 WINED3DSAMP_ADDRESSV ,
8042 WINED3DSAMP_ADDRESSW ,
8043 WINED3DSAMP_BORDERCOLOR ,
8044 WINED3DSAMP_MAGFILTER ,
8045 WINED3DSAMP_MINFILTER ,
8046 WINED3DSAMP_MIPFILTER ,
8047 WINED3DSAMP_MIPMAPLODBIAS ,
8048 WINED3DSAMP_MAXMIPLEVEL ,
8049 WINED3DSAMP_MAXANISOTROPY ,
8050 WINED3DSAMP_SRGBTEXTURE ,
8051 WINED3DSAMP_ELEMENTINDEX
8054 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8055 WINED3DRS_AMBIENT ,
8056 WINED3DRS_AMBIENTMATERIALSOURCE ,
8057 WINED3DRS_CLIPPING ,
8058 WINED3DRS_CLIPPLANEENABLE ,
8059 WINED3DRS_COLORVERTEX ,
8060 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8061 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8062 WINED3DRS_FOGDENSITY ,
8063 WINED3DRS_FOGEND ,
8064 WINED3DRS_FOGSTART ,
8065 WINED3DRS_FOGTABLEMODE ,
8066 WINED3DRS_FOGVERTEXMODE ,
8067 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8068 WINED3DRS_LIGHTING ,
8069 WINED3DRS_LOCALVIEWER ,
8070 WINED3DRS_MULTISAMPLEANTIALIAS ,
8071 WINED3DRS_MULTISAMPLEMASK ,
8072 WINED3DRS_NORMALIZENORMALS ,
8073 WINED3DRS_PATCHEDGESTYLE ,
8074 WINED3DRS_POINTSCALE_A ,
8075 WINED3DRS_POINTSCALE_B ,
8076 WINED3DRS_POINTSCALE_C ,
8077 WINED3DRS_POINTSCALEENABLE ,
8078 WINED3DRS_POINTSIZE ,
8079 WINED3DRS_POINTSIZE_MAX ,
8080 WINED3DRS_POINTSIZE_MIN ,
8081 WINED3DRS_POINTSPRITEENABLE ,
8082 WINED3DRS_RANGEFOGENABLE ,
8083 WINED3DRS_SPECULARMATERIALSOURCE ,
8084 WINED3DRS_TWEENFACTOR ,
8085 WINED3DRS_VERTEXBLEND ,
8086 WINED3DRS_CULLMODE ,
8087 WINED3DRS_FOGCOLOR
8090 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8091 WINED3DTSS_TEXCOORDINDEX ,
8092 WINED3DTSS_TEXTURETRANSFORMFLAGS
8095 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8096 WINED3DSAMP_DMAPOFFSET
8099 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8100 DWORD rep = This->StateTable[state].representative;
8101 DWORD idx;
8102 BYTE shift;
8103 UINT i;
8104 WineD3DContext *context;
8106 if(!rep) return;
8107 for(i = 0; i < This->numContexts; i++) {
8108 context = This->contexts[i];
8109 if(isStateDirty(context, rep)) continue;
8111 context->dirtyArray[context->numDirtyEntries++] = rep;
8112 idx = rep >> 5;
8113 shift = rep & 0x1f;
8114 context->isStateDirty[idx] |= (1 << shift);
8118 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8119 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8120 /* The drawable size of a pbuffer render target is the current pbuffer size
8122 *width = dev->pbufferWidth;
8123 *height = dev->pbufferHeight;
8126 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8127 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8129 *width = This->pow2Width;
8130 *height = This->pow2Height;
8133 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8134 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8135 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8136 * current context's drawable, which is the size of the back buffer of the swapchain
8137 * the active context belongs to. The back buffer of the swapchain is stored as the
8138 * surface the context belongs to.
8140 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8141 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;