push 0e883ac4a03c91e56787e1ec12e001b6558b4b62
[wine/hacks.git] / dlls / wined3d / device.c
blob2263fd88eb596e35f60f0e63cedbfea6131be4c7
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-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
193 This = NULL;
195 return refCount;
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
205 return WINED3D_OK;
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
210 IUnknown *parent) {
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
215 BOOL conv;
217 if(Size == 0) {
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 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);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
235 object->fvf = FVF;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
248 * dx7 apps.
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
261 } else {
262 object->Flags |= VBFLAG_CREATEVBO;
264 return WINED3D_OK;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
278 ENTER_GL();
280 while(glGetError());
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 goto out;
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 goto out;
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
304 goto out;
306 LEAVE_GL();
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
308 return;
310 out:
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
313 LEAVE_GL();
314 object->vbo = 0;
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
335 return WINED3D_OK;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
342 int i, j;
343 HRESULT temp_result;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
357 return WINED3D_OK;
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
362 return temp_result;
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
367 else
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
372 object->ref = 1;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
384 struct list *e;
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
584 /* ************************************
585 MSDN:
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
588 Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 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.
593 ******************************** */
595 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) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
603 * MSDN
604 * MultisampleQuality
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 * must all match.
610 *******************************/
614 * TODO: Discard MSDN
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
630 * by the device.
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
635 * space!
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
638 Size = 0;
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
645 Format == WINED3DFMT_ATI2N) {
646 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
647 } else {
648 /* The pitch is a multiple of 4 bytes */
649 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
650 Size *= Height;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
663 list_init(&object->overlays);
665 /* Flags */
666 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Look at the implementation and set the correct Vtable */
722 switch(Impl) {
723 case SURFACE_OPENGL:
724 /* Check if a 3D adapter is available when creating gl surfaces */
725 if(!This->adapter) {
726 ERR("OpenGL surfaces are not available without opengl\n");
727 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
728 HeapFree(GetProcessHeap(), 0, object);
729 return WINED3DERR_NOTAVAILABLE;
731 break;
733 case SURFACE_GDI:
734 object->lpVtbl = &IWineGDISurface_Vtbl;
735 break;
737 default:
738 /* To be sure to catch this */
739 ERR("Unknown requested surface implementation %d!\n", Impl);
740 IWineD3DSurface_Release((IWineD3DSurface *) object);
741 return WINED3DERR_INVALIDCALL;
744 list_init(&object->renderbuffers);
746 /* Call the private setup routine */
747 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
751 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
752 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
753 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
754 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
757 IWineD3DTextureImpl *object;
758 unsigned int i;
759 UINT tmpW;
760 UINT tmpH;
761 HRESULT hr;
762 unsigned int pow2Width;
763 unsigned int pow2Height;
764 const GlPixelFormatDesc *glDesc;
765 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
767 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
768 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
769 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
771 /* TODO: It should only be possible to create textures for formats
772 that are reported as supported */
773 if (WINED3DFMT_UNKNOWN >= Format) {
774 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
775 return WINED3DERR_INVALIDCALL;
778 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
779 D3DINITIALIZEBASETEXTURE(object->baseTexture);
780 object->width = Width;
781 object->height = Height;
783 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
784 object->baseTexture.minMipLookup = &minMipLookup;
785 object->baseTexture.magLookup = &magLookup;
786 } else {
787 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
788 object->baseTexture.magLookup = &magLookup_noFilter;
791 /** Non-power2 support **/
792 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
793 pow2Width = Width;
794 pow2Height = Height;
795 } else {
796 /* Find the nearest pow2 match */
797 pow2Width = pow2Height = 1;
798 while (pow2Width < Width) pow2Width <<= 1;
799 while (pow2Height < Height) pow2Height <<= 1;
801 if(pow2Width != Width || pow2Height != Height) {
802 if(Levels > 1) {
803 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
804 HeapFree(GetProcessHeap(), 0, object);
805 *ppTexture = NULL;
806 return WINED3DERR_INVALIDCALL;
807 } else {
808 Levels = 1;
813 /** FIXME: add support for real non-power-two if it's provided by the video card **/
814 /* Precalculated scaling for 'faked' non power of two texture coords.
815 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
816 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
817 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
819 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
820 object->baseTexture.pow2Matrix[0] = 1.0;
821 object->baseTexture.pow2Matrix[5] = 1.0;
822 object->baseTexture.pow2Matrix[10] = 1.0;
823 object->baseTexture.pow2Matrix[15] = 1.0;
824 object->target = GL_TEXTURE_2D;
825 object->cond_np2 = TRUE;
826 pow2Width = Width;
827 pow2Height = Height;
828 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
829 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
830 (Width != pow2Width || Height != pow2Height) &&
831 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
833 object->baseTexture.pow2Matrix[0] = (float)Width;
834 object->baseTexture.pow2Matrix[5] = (float)Height;
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_RECTANGLE_ARB;
838 object->cond_np2 = TRUE;
839 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
840 } else {
841 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
842 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
843 object->baseTexture.pow2Matrix[10] = 1.0;
844 object->baseTexture.pow2Matrix[15] = 1.0;
845 object->target = GL_TEXTURE_2D;
846 object->cond_np2 = FALSE;
848 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
850 /* Calculate levels for mip mapping */
851 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
852 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
853 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL;
856 if(Levels > 1) {
857 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
858 return WINED3DERR_INVALIDCALL;
860 object->baseTexture.levels = 1;
861 } else if (Levels == 0) {
862 TRACE("calculating levels %d\n", object->baseTexture.levels);
863 object->baseTexture.levels++;
864 tmpW = Width;
865 tmpH = Height;
866 while (tmpW > 1 || tmpH > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 object->baseTexture.levels++;
871 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
874 /* Generate all the surfaces */
875 tmpW = Width;
876 tmpH = Height;
877 for (i = 0; i < object->baseTexture.levels; i++)
879 /* use the callback to create the texture surface */
880 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
881 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
882 FIXME("Failed to create surface %p\n", object);
883 /* clean up */
884 object->surfaces[i] = NULL;
885 IWineD3DTexture_Release((IWineD3DTexture *)object);
887 *ppTexture = NULL;
888 return hr;
891 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
892 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
893 /* calculate the next mipmap level */
894 tmpW = max(1, tmpW >> 1);
895 tmpH = max(1, tmpH >> 1);
897 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
899 TRACE("(%p) : Created texture %p\n", This, object);
900 return WINED3D_OK;
903 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
904 UINT Width, UINT Height, UINT Depth,
905 UINT Levels, DWORD Usage,
906 WINED3DFORMAT Format, WINED3DPOOL Pool,
907 IWineD3DVolumeTexture **ppVolumeTexture,
908 HANDLE *pSharedHandle, IUnknown *parent,
909 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DVolumeTextureImpl *object;
913 unsigned int i;
914 UINT tmpW;
915 UINT tmpH;
916 UINT tmpD;
917 const GlPixelFormatDesc *glDesc;
919 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN >= Format) {
924 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
925 return WINED3DERR_INVALIDCALL;
927 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
928 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
929 return WINED3DERR_INVALIDCALL;
932 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
933 D3DINITIALIZEBASETEXTURE(object->baseTexture);
935 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
936 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
938 object->width = Width;
939 object->height = Height;
940 object->depth = Depth;
942 /* Is NP2 support for volumes needed? */
943 object->baseTexture.pow2Matrix[ 0] = 1.0;
944 object->baseTexture.pow2Matrix[ 5] = 1.0;
945 object->baseTexture.pow2Matrix[10] = 1.0;
946 object->baseTexture.pow2Matrix[15] = 1.0;
948 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
949 object->baseTexture.minMipLookup = &minMipLookup;
950 object->baseTexture.magLookup = &magLookup;
951 } else {
952 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
953 object->baseTexture.magLookup = &magLookup_noFilter;
956 /* Calculate levels for mip mapping */
957 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
958 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
959 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
960 return WINED3DERR_INVALIDCALL;
962 if(Levels > 1) {
963 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL;
966 Levels = 1;
967 } else if (Levels == 0) {
968 object->baseTexture.levels++;
969 tmpW = Width;
970 tmpH = Height;
971 tmpD = Depth;
972 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
973 tmpW = max(1, tmpW >> 1);
974 tmpH = max(1, tmpH >> 1);
975 tmpD = max(1, tmpD >> 1);
976 object->baseTexture.levels++;
978 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
981 /* Generate all the surfaces */
982 tmpW = Width;
983 tmpH = Height;
984 tmpD = Depth;
986 for (i = 0; i < object->baseTexture.levels; i++)
988 HRESULT hr;
989 /* Create the volume */
990 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
991 &object->volumes[i], pSharedHandle);
993 if(FAILED(hr)) {
994 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
995 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
996 *ppVolumeTexture = NULL;
997 return hr;
1000 /* Set its container to this object */
1001 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1003 /* calculate the next mipmap level */
1004 tmpW = max(1, tmpW >> 1);
1005 tmpH = max(1, tmpH >> 1);
1006 tmpD = max(1, tmpD >> 1);
1008 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1010 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1011 TRACE("(%p) : Created volume texture %p\n", This, object);
1012 return WINED3D_OK;
1015 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1016 UINT Width, UINT Height, UINT Depth,
1017 DWORD Usage,
1018 WINED3DFORMAT Format, WINED3DPOOL Pool,
1019 IWineD3DVolume** ppVolume,
1020 HANDLE* pSharedHandle, IUnknown *parent) {
1022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1023 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1024 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1026 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1027 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1028 return WINED3DERR_INVALIDCALL;
1031 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1033 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1034 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1036 object->currentDesc.Width = Width;
1037 object->currentDesc.Height = Height;
1038 object->currentDesc.Depth = Depth;
1039 object->bytesPerPixel = formatDesc->bpp;
1041 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1042 object->lockable = TRUE;
1043 object->locked = FALSE;
1044 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1045 object->dirty = TRUE;
1047 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1050 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1051 UINT Levels, DWORD Usage,
1052 WINED3DFORMAT Format, WINED3DPOOL Pool,
1053 IWineD3DCubeTexture **ppCubeTexture,
1054 HANDLE *pSharedHandle, IUnknown *parent,
1055 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1058 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int i, j;
1060 UINT tmpW;
1061 HRESULT hr;
1062 unsigned int pow2EdgeLength = EdgeLength;
1063 const GlPixelFormatDesc *glDesc;
1064 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1066 /* TODO: It should only be possible to create textures for formats
1067 that are reported as supported */
1068 if (WINED3DFMT_UNKNOWN >= Format) {
1069 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1070 return WINED3DERR_INVALIDCALL;
1073 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1074 WARN("(%p) : Tried to create not supported cube texture\n", This);
1075 return WINED3DERR_INVALIDCALL;
1078 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1079 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1081 TRACE("(%p) Create Cube Texture\n", This);
1083 /** Non-power2 support **/
1085 /* Find the nearest pow2 match */
1086 pow2EdgeLength = 1;
1087 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1089 object->edgeLength = EdgeLength;
1090 /* TODO: support for native non-power 2 */
1091 /* Precalculated scaling for 'faked' non power of two texture coords */
1092 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1093 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1094 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1095 object->baseTexture.pow2Matrix[15] = 1.0;
1097 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1098 object->baseTexture.minMipLookup = &minMipLookup;
1099 object->baseTexture.magLookup = &magLookup;
1100 } else {
1101 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1102 object->baseTexture.magLookup = &magLookup_noFilter;
1105 /* Calculate levels for mip mapping */
1106 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1107 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1108 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1109 HeapFree(GetProcessHeap(), 0, object);
1110 *ppCubeTexture = NULL;
1112 return WINED3DERR_INVALIDCALL;
1114 if(Levels > 1) {
1115 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1116 HeapFree(GetProcessHeap(), 0, object);
1117 *ppCubeTexture = NULL;
1119 return WINED3DERR_INVALIDCALL;
1121 Levels = 1;
1122 } else if (Levels == 0) {
1123 object->baseTexture.levels++;
1124 tmpW = EdgeLength;
1125 while (tmpW > 1) {
1126 tmpW = max(1, tmpW >> 1);
1127 object->baseTexture.levels++;
1129 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1132 /* Generate all the surfaces */
1133 tmpW = EdgeLength;
1134 for (i = 0; i < object->baseTexture.levels; i++) {
1136 /* Create the 6 faces */
1137 for (j = 0; j < 6; j++) {
1139 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1140 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1142 if(hr!= WINED3D_OK) {
1143 /* clean up */
1144 int k;
1145 int l;
1146 for (l = 0; l < j; l++) {
1147 IWineD3DSurface_Release(object->surfaces[l][i]);
1149 for (k = 0; k < i; k++) {
1150 for (l = 0; l < 6; l++) {
1151 IWineD3DSurface_Release(object->surfaces[l][k]);
1155 FIXME("(%p) Failed to create surface\n",object);
1156 HeapFree(GetProcessHeap(),0,object);
1157 *ppCubeTexture = NULL;
1158 return hr;
1160 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1161 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1163 tmpW = max(1, tmpW >> 1);
1165 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1167 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1168 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1169 return WINED3D_OK;
1172 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1175 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1176 const IWineD3DQueryVtbl *vtable;
1178 /* Just a check to see if we support this type of query */
1179 switch(Type) {
1180 case WINED3DQUERYTYPE_OCCLUSION:
1181 TRACE("(%p) occlusion query\n", This);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1183 hr = WINED3D_OK;
1184 else
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1187 vtable = &IWineD3DOcclusionQuery_Vtbl;
1188 break;
1190 case WINED3DQUERYTYPE_EVENT:
1191 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1192 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1193 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1195 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1197 vtable = &IWineD3DEventQuery_Vtbl;
1198 hr = WINED3D_OK;
1199 break;
1201 case WINED3DQUERYTYPE_VCACHE:
1202 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1203 case WINED3DQUERYTYPE_VERTEXSTATS:
1204 case WINED3DQUERYTYPE_TIMESTAMP:
1205 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1206 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1207 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1208 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1209 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1210 case WINED3DQUERYTYPE_PIXELTIMINGS:
1211 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1212 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1213 default:
1214 /* Use the base Query vtable until we have a special one for each query */
1215 vtable = &IWineD3DQuery_Vtbl;
1216 FIXME("(%p) Unhandled query type %d\n", This, Type);
1218 if(NULL == ppQuery || hr != WINED3D_OK) {
1219 return hr;
1222 D3DCREATEOBJECTINSTANCE(object, Query)
1223 object->lpVtbl = vtable;
1224 object->type = Type;
1225 object->state = QUERY_CREATED;
1226 /* allocated the 'extended' data based on the type of query requested */
1227 switch(Type){
1228 case WINED3DQUERYTYPE_OCCLUSION:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1230 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1232 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1233 TRACE("(%p) Allocating data for an occlusion query\n", This);
1234 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1235 break;
1237 case WINED3DQUERYTYPE_EVENT:
1238 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1239 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1241 if(GL_SUPPORT(APPLE_FENCE)) {
1242 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1243 checkGLcall("glGenFencesAPPLE");
1244 } else if(GL_SUPPORT(NV_FENCE)) {
1245 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesNV");
1248 break;
1250 case WINED3DQUERYTYPE_VCACHE:
1251 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1252 case WINED3DQUERYTYPE_VERTEXSTATS:
1253 case WINED3DQUERYTYPE_TIMESTAMP:
1254 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1255 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1256 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1257 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1258 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1259 case WINED3DQUERYTYPE_PIXELTIMINGS:
1260 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1261 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1262 default:
1263 object->extendedData = 0;
1264 FIXME("(%p) Unhandled query type %d\n",This , Type);
1266 TRACE("(%p) : Created Query %p\n", This, object);
1267 return WINED3D_OK;
1270 /*****************************************************************************
1271 * IWineD3DDeviceImpl_SetupFullscreenWindow
1273 * Helper function that modifies a HWND's Style and ExStyle for proper
1274 * fullscreen use.
1276 * Params:
1277 * iface: Pointer to the IWineD3DDevice interface
1278 * window: Window to setup
1280 *****************************************************************************/
1281 static LONG fullscreen_style(LONG orig_style) {
1282 LONG style = orig_style;
1283 style &= ~WS_CAPTION;
1284 style &= ~WS_THICKFRAME;
1286 /* Make sure the window is managed, otherwise we won't get keyboard input */
1287 style |= WS_POPUP | WS_SYSMENU;
1289 return style;
1292 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1293 LONG exStyle = orig_exStyle;
1295 /* Filter out window decorations */
1296 exStyle &= ~WS_EX_WINDOWEDGE;
1297 exStyle &= ~WS_EX_CLIENTEDGE;
1299 return exStyle;
1302 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 LONG style, exStyle;
1306 /* Don't do anything if an original style is stored.
1307 * That shouldn't happen
1309 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1310 if (This->style || This->exStyle) {
1311 ERR("(%p): Want to change the window parameters of HWND %p, but "
1312 "another style is stored for restoration afterwards\n", This, window);
1315 /* Get the parameters and save them */
1316 style = GetWindowLongW(window, GWL_STYLE);
1317 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1318 This->style = style;
1319 This->exStyle = exStyle;
1321 style = fullscreen_style(style);
1322 exStyle = fullscreen_exStyle(exStyle);
1324 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1325 This->style, This->exStyle, style, exStyle);
1327 SetWindowLongW(window, GWL_STYLE, style);
1328 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1330 /* Inform the window about the update. */
1331 SetWindowPos(window, HWND_TOP, 0, 0,
1332 w, h, SWP_FRAMECHANGED);
1333 ShowWindow(window, SW_NORMAL);
1336 /*****************************************************************************
1337 * IWineD3DDeviceImpl_RestoreWindow
1339 * Helper function that restores a windows' properties when taking it out
1340 * of fullscreen mode
1342 * Params:
1343 * iface: Pointer to the IWineD3DDevice interface
1344 * window: Window to setup
1346 *****************************************************************************/
1347 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1349 LONG style, exStyle;
1351 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1352 * switch, do nothing
1354 if (!This->style && !This->exStyle) return;
1356 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1357 This, window, This->style, This->exStyle);
1359 style = GetWindowLongW(window, GWL_STYLE);
1360 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1362 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1363 * Some applications change it before calling Reset() when switching between windowed and
1364 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1366 if(style == fullscreen_style(This->style) &&
1367 exStyle == fullscreen_style(This->exStyle)) {
1368 SetWindowLongW(window, GWL_STYLE, This->style);
1369 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1372 /* Delete the old values */
1373 This->style = 0;
1374 This->exStyle = 0;
1376 /* Inform the window about the update */
1377 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1378 0, 0, 0, 0, /* Pos, Size, ignored */
1379 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1382 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1384 IUnknown* parent,
1385 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1386 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1387 WINED3DSURFTYPE surface_type) {
1388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1390 HDC hDc;
1391 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1392 HRESULT hr = WINED3D_OK;
1393 IUnknown *bufferParent;
1394 BOOL displaymode_set = FALSE;
1395 WINED3DDISPLAYMODE Mode;
1396 const StaticPixelFormatDesc *formatDesc;
1398 TRACE("(%p) : Created Additional Swap Chain\n", This);
1400 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1401 * does a device hold a reference to a swap chain giving them a lifetime of the device
1402 * or does the swap chain notify the device of its destruction.
1403 *******************************/
1405 /* Check the params */
1406 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1407 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1408 return WINED3DERR_INVALIDCALL;
1409 } else if (pPresentationParameters->BackBufferCount > 1) {
1410 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");
1413 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1414 switch(surface_type) {
1415 case SURFACE_GDI:
1416 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1417 break;
1418 case SURFACE_OPENGL:
1419 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1420 break;
1421 case SURFACE_UNKNOWN:
1422 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1423 return WINED3DERR_INVALIDCALL;
1426 /*********************
1427 * Lookup the window Handle and the relating X window handle
1428 ********************/
1430 /* Setup hwnd we are using, plus which display this equates to */
1431 object->win_handle = pPresentationParameters->hDeviceWindow;
1432 if (!object->win_handle) {
1433 object->win_handle = This->createParms.hFocusWindow;
1435 if(!pPresentationParameters->Windowed && object->win_handle) {
1436 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1437 pPresentationParameters->BackBufferWidth,
1438 pPresentationParameters->BackBufferHeight);
1441 hDc = GetDC(object->win_handle);
1442 TRACE("Using hDc %p\n", hDc);
1444 if (NULL == hDc) {
1445 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1446 return WINED3DERR_NOTAVAILABLE;
1449 /* Get info on the current display setup */
1450 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1451 object->orig_width = Mode.Width;
1452 object->orig_height = Mode.Height;
1453 object->orig_fmt = Mode.Format;
1454 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1456 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1457 * then the corresponding dimension of the client area of the hDeviceWindow
1458 * (or the focus window, if hDeviceWindow is NULL) is taken.
1459 **********************/
1461 if (pPresentationParameters->Windowed &&
1462 ((pPresentationParameters->BackBufferWidth == 0) ||
1463 (pPresentationParameters->BackBufferHeight == 0) ||
1464 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1466 RECT Rect;
1467 GetClientRect(object->win_handle, &Rect);
1469 if (pPresentationParameters->BackBufferWidth == 0) {
1470 pPresentationParameters->BackBufferWidth = Rect.right;
1471 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1473 if (pPresentationParameters->BackBufferHeight == 0) {
1474 pPresentationParameters->BackBufferHeight = Rect.bottom;
1475 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1477 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1478 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1479 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1483 /* Put the correct figures in the presentation parameters */
1484 TRACE("Copying across presentation parameters\n");
1485 object->presentParms = *pPresentationParameters;
1487 TRACE("calling rendertarget CB\n");
1488 hr = D3DCB_CreateRenderTarget(This->parent,
1489 parent,
1490 object->presentParms.BackBufferWidth,
1491 object->presentParms.BackBufferHeight,
1492 object->presentParms.BackBufferFormat,
1493 object->presentParms.MultiSampleType,
1494 object->presentParms.MultiSampleQuality,
1495 TRUE /* Lockable */,
1496 &object->frontBuffer,
1497 NULL /* pShared (always null)*/);
1498 if (object->frontBuffer != NULL) {
1499 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1500 if(surface_type == SURFACE_OPENGL) {
1501 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1503 } else {
1504 ERR("Failed to create the front buffer\n");
1505 goto error;
1508 /*********************
1509 * Windowed / Fullscreen
1510 *******************/
1513 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1514 * so we should really check to see if there is a fullscreen swapchain already
1515 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1516 **************************************/
1518 if (!pPresentationParameters->Windowed) {
1519 WINED3DDISPLAYMODE mode;
1522 /* Change the display settings */
1523 mode.Width = pPresentationParameters->BackBufferWidth;
1524 mode.Height = pPresentationParameters->BackBufferHeight;
1525 mode.Format = pPresentationParameters->BackBufferFormat;
1526 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1528 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1529 displaymode_set = TRUE;
1533 * Create an opengl context for the display visual
1534 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1535 * use different properties after that point in time. FIXME: How to handle when requested format
1536 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1537 * it chooses is identical to the one already being used!
1538 **********************************/
1539 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1541 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1542 if(!object->context)
1543 return E_OUTOFMEMORY;
1544 object->num_contexts = 1;
1546 if(surface_type == SURFACE_OPENGL) {
1547 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1548 if (!object->context[0]) {
1549 ERR("Failed to create a new context\n");
1550 hr = WINED3DERR_NOTAVAILABLE;
1551 goto error;
1552 } else {
1553 TRACE("Context created (HWND=%p, glContext=%p)\n",
1554 object->win_handle, object->context[0]->glCtx);
1558 /*********************
1559 * Create the back, front and stencil buffers
1560 *******************/
1561 if(object->presentParms.BackBufferCount > 0) {
1562 int i;
1564 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1565 if(!object->backBuffer) {
1566 ERR("Out of memory\n");
1567 hr = E_OUTOFMEMORY;
1568 goto error;
1571 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1572 TRACE("calling rendertarget CB\n");
1573 hr = D3DCB_CreateRenderTarget(This->parent,
1574 parent,
1575 object->presentParms.BackBufferWidth,
1576 object->presentParms.BackBufferHeight,
1577 object->presentParms.BackBufferFormat,
1578 object->presentParms.MultiSampleType,
1579 object->presentParms.MultiSampleQuality,
1580 TRUE /* Lockable */,
1581 &object->backBuffer[i],
1582 NULL /* pShared (always null)*/);
1583 if(hr == WINED3D_OK && object->backBuffer[i]) {
1584 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1585 } else {
1586 ERR("Cannot create new back buffer\n");
1587 goto error;
1589 if(surface_type == SURFACE_OPENGL) {
1590 ENTER_GL();
1591 glDrawBuffer(GL_BACK);
1592 checkGLcall("glDrawBuffer(GL_BACK)");
1593 LEAVE_GL();
1596 } else {
1597 object->backBuffer = NULL;
1599 /* Single buffering - draw to front buffer */
1600 if(surface_type == SURFACE_OPENGL) {
1601 ENTER_GL();
1602 glDrawBuffer(GL_FRONT);
1603 checkGLcall("glDrawBuffer(GL_FRONT)");
1604 LEAVE_GL();
1608 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1609 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1610 TRACE("Creating depth stencil buffer\n");
1611 if (This->auto_depth_stencil_buffer == NULL ) {
1612 hr = D3DCB_CreateDepthStencil(This->parent,
1613 parent,
1614 object->presentParms.BackBufferWidth,
1615 object->presentParms.BackBufferHeight,
1616 object->presentParms.AutoDepthStencilFormat,
1617 object->presentParms.MultiSampleType,
1618 object->presentParms.MultiSampleQuality,
1619 FALSE /* FIXME: Discard */,
1620 &This->auto_depth_stencil_buffer,
1621 NULL /* pShared (always null)*/ );
1622 if (This->auto_depth_stencil_buffer != NULL)
1623 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1626 /** TODO: A check on width, height and multisample types
1627 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1628 ****************************/
1629 object->wantsDepthStencilBuffer = TRUE;
1630 } else {
1631 object->wantsDepthStencilBuffer = FALSE;
1634 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1636 TRACE("Created swapchain %p\n", object);
1637 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1638 return WINED3D_OK;
1640 error:
1641 if (displaymode_set) {
1642 DEVMODEW devmode;
1643 RECT clip_rc;
1645 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1646 ClipCursor(NULL);
1648 /* Change the display settings */
1649 memset(&devmode, 0, sizeof(devmode));
1650 devmode.dmSize = sizeof(devmode);
1651 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1652 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1653 devmode.dmPelsWidth = object->orig_width;
1654 devmode.dmPelsHeight = object->orig_height;
1655 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1658 if (object->backBuffer) {
1659 int i;
1660 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1661 if(object->backBuffer[i]) {
1662 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1663 IUnknown_Release(bufferParent); /* once for the get parent */
1664 if (IUnknown_Release(bufferParent) > 0) {
1665 FIXME("(%p) Something's still holding the back buffer\n",This);
1669 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1670 object->backBuffer = NULL;
1672 if(object->context[0])
1673 DestroyContext(This, object->context[0]);
1674 if(object->frontBuffer) {
1675 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1676 IUnknown_Release(bufferParent); /* once for the get parent */
1677 if (IUnknown_Release(bufferParent) > 0) {
1678 FIXME("(%p) Something's still holding the front buffer\n",This);
1681 HeapFree(GetProcessHeap(), 0, object);
1682 return hr;
1685 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1686 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p)\n", This);
1690 return This->NumberOfSwapChains;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1697 if(iSwapChain < This->NumberOfSwapChains) {
1698 *pSwapChain = This->swapchains[iSwapChain];
1699 IWineD3DSwapChain_AddRef(*pSwapChain);
1700 TRACE("(%p) returning %p\n", This, *pSwapChain);
1701 return WINED3D_OK;
1702 } else {
1703 TRACE("Swapchain out of range\n");
1704 *pSwapChain = NULL;
1705 return WINED3DERR_INVALIDCALL;
1709 /*****
1710 * Vertex Declaration
1711 *****/
1712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1713 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1715 IWineD3DVertexDeclarationImpl *object = NULL;
1716 HRESULT hr = WINED3D_OK;
1718 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1719 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1721 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1723 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1724 if(FAILED(hr)) {
1725 *ppVertexDeclaration = NULL;
1726 HeapFree(GetProcessHeap(), 0, object);
1729 return hr;
1732 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1733 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1735 unsigned int idx, idx2;
1736 unsigned int offset;
1737 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1738 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1739 BOOL has_blend_idx = has_blend &&
1740 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1741 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1742 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1743 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1744 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1745 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1746 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1748 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1749 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1751 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1752 WINED3DVERTEXELEMENT *elements = NULL;
1754 unsigned int size;
1755 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1756 if (has_blend_idx) num_blends--;
1758 /* Compute declaration size */
1759 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1760 has_psize + has_diffuse + has_specular + num_textures + 1;
1762 /* convert the declaration */
1763 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1764 if (!elements)
1765 return 0;
1767 elements[size-1] = end_element;
1768 idx = 0;
1769 if (has_pos) {
1770 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1772 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1774 else {
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1776 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1778 elements[idx].UsageIndex = 0;
1779 idx++;
1781 if (has_blend && (num_blends > 0)) {
1782 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1783 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1784 else
1785 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1786 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1787 elements[idx].UsageIndex = 0;
1788 idx++;
1790 if (has_blend_idx) {
1791 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1792 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1793 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1794 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1796 else
1797 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1798 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1799 elements[idx].UsageIndex = 0;
1800 idx++;
1802 if (has_normal) {
1803 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1804 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1805 elements[idx].UsageIndex = 0;
1806 idx++;
1808 if (has_psize) {
1809 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1811 elements[idx].UsageIndex = 0;
1812 idx++;
1814 if (has_diffuse) {
1815 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1816 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1817 elements[idx].UsageIndex = 0;
1818 idx++;
1820 if (has_specular) {
1821 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1822 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1823 elements[idx].UsageIndex = 1;
1824 idx++;
1826 for (idx2 = 0; idx2 < num_textures; idx2++) {
1827 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1828 switch (numcoords) {
1829 case WINED3DFVF_TEXTUREFORMAT1:
1830 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1831 break;
1832 case WINED3DFVF_TEXTUREFORMAT2:
1833 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1834 break;
1835 case WINED3DFVF_TEXTUREFORMAT3:
1836 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1837 break;
1838 case WINED3DFVF_TEXTUREFORMAT4:
1839 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1840 break;
1842 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1843 elements[idx].UsageIndex = idx2;
1844 idx++;
1847 /* Now compute offsets, and initialize the rest of the fields */
1848 for (idx = 0, offset = 0; idx < size-1; idx++) {
1849 elements[idx].Stream = 0;
1850 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1851 elements[idx].Offset = offset;
1852 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1855 *ppVertexElements = elements;
1856 return size;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1860 WINED3DVERTEXELEMENT* elements = NULL;
1861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1862 unsigned int size;
1863 DWORD hr;
1865 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1866 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1868 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1869 HeapFree(GetProcessHeap(), 0, elements);
1870 if (hr != S_OK) return hr;
1872 return WINED3D_OK;
1875 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1877 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1878 HRESULT hr = WINED3D_OK;
1879 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1880 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1882 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1884 if (vertex_declaration) {
1885 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1888 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1890 if (WINED3D_OK != hr) {
1891 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1892 IWineD3DVertexShader_Release(*ppVertexShader);
1893 return WINED3DERR_INVALIDCALL;
1895 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1897 return WINED3D_OK;
1900 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1902 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1903 HRESULT hr = WINED3D_OK;
1905 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1906 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1907 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1908 if (WINED3D_OK == hr) {
1909 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1910 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1911 } else {
1912 WARN("(%p) : Failed to create pixel shader\n", This);
1915 return hr;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 IWineD3DPaletteImpl *object;
1921 HRESULT hr;
1922 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1924 /* Create the new object */
1925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1926 if(!object) {
1927 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1928 return E_OUTOFMEMORY;
1931 object->lpVtbl = &IWineD3DPalette_Vtbl;
1932 object->ref = 1;
1933 object->Flags = Flags;
1934 object->parent = Parent;
1935 object->wineD3DDevice = This;
1936 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1938 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1940 if(!object->hpal) {
1941 HeapFree( GetProcessHeap(), 0, object);
1942 return E_OUTOFMEMORY;
1945 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1946 if(FAILED(hr)) {
1947 IWineD3DPalette_Release((IWineD3DPalette *) object);
1948 return hr;
1951 *Palette = (IWineD3DPalette *) object;
1953 return WINED3D_OK;
1956 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1957 HBITMAP hbm;
1958 BITMAP bm;
1959 HRESULT hr;
1960 HDC dcb = NULL, dcs = NULL;
1961 WINEDDCOLORKEY colorkey;
1963 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1964 if(hbm)
1966 GetObjectA(hbm, sizeof(BITMAP), &bm);
1967 dcb = CreateCompatibleDC(NULL);
1968 if(!dcb) goto out;
1969 SelectObject(dcb, hbm);
1971 else
1973 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1974 * couldn't be loaded
1976 memset(&bm, 0, sizeof(bm));
1977 bm.bmWidth = 32;
1978 bm.bmHeight = 32;
1981 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1982 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1983 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1984 if(FAILED(hr)) {
1985 ERR("Wine logo requested, but failed to create surface\n");
1986 goto out;
1989 if(dcb) {
1990 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1991 if(FAILED(hr)) goto out;
1992 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1993 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1995 colorkey.dwColorSpaceLowValue = 0;
1996 colorkey.dwColorSpaceHighValue = 0;
1997 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1998 } else {
1999 /* Fill the surface with a white color to show that wined3d is there */
2000 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2003 out:
2004 if(dcb) {
2005 DeleteDC(dcb);
2007 if(hbm) {
2008 DeleteObject(hbm);
2010 return;
2013 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2014 unsigned int i;
2015 /* Under DirectX you can have texture stage operations even if no texture is
2016 bound, whereas opengl will only do texture operations when a valid texture is
2017 bound. We emulate this by creating dummy textures and binding them to each
2018 texture stage, but disable all stages by default. Hence if a stage is enabled
2019 then the default texture will kick in until replaced by a SetTexture call */
2020 ENTER_GL();
2022 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2023 /* The dummy texture does not have client storage backing */
2024 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2025 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2027 for (i = 0; i < GL_LIMITS(textures); i++) {
2028 GLubyte white = 255;
2030 /* Make appropriate texture active */
2031 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2032 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2033 checkGLcall("glActiveTextureARB");
2034 } else if (i > 0) {
2035 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2038 /* Generate an opengl texture name */
2039 glGenTextures(1, &This->dummyTextureName[i]);
2040 checkGLcall("glGenTextures");
2041 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2043 /* Generate a dummy 2d texture (not using 1d because they cause many
2044 * DRI drivers fall back to sw) */
2045 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2046 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2047 checkGLcall("glBindTexture");
2049 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2050 checkGLcall("glTexImage2D");
2052 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2053 /* Reenable because if supported it is enabled by default */
2054 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2055 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2058 LEAVE_GL();
2061 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2063 IWineD3DSwapChainImpl *swapchain = NULL;
2064 HRESULT hr;
2065 DWORD state;
2066 unsigned int i;
2068 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2069 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2070 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2072 /* TODO: Test if OpenGL is compiled in and loaded */
2074 TRACE("(%p) : Creating stateblock\n", This);
2075 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2076 hr = IWineD3DDevice_CreateStateBlock(iface,
2077 WINED3DSBT_INIT,
2078 (IWineD3DStateBlock **)&This->stateBlock,
2079 NULL);
2080 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2081 WARN("Failed to create stateblock\n");
2082 goto err_out;
2084 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2085 This->updateStateBlock = This->stateBlock;
2086 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2088 hr = allocate_shader_constants(This->updateStateBlock);
2089 if (WINED3D_OK != hr) {
2090 goto err_out;
2093 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2094 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2095 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2097 This->NumberOfPalettes = 1;
2098 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2099 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2100 ERR("Out of memory!\n");
2101 goto err_out;
2103 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2104 if(!This->palettes[0]) {
2105 ERR("Out of memory!\n");
2106 goto err_out;
2108 for (i = 0; i < 256; ++i) {
2109 This->palettes[0][i].peRed = 0xFF;
2110 This->palettes[0][i].peGreen = 0xFF;
2111 This->palettes[0][i].peBlue = 0xFF;
2112 This->palettes[0][i].peFlags = 0xFF;
2114 This->currentPalette = 0;
2116 /* Initialize the texture unit mapping to a 1:1 mapping */
2117 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2118 if (state < GL_LIMITS(fragment_samplers)) {
2119 This->texUnitMap[state] = state;
2120 This->rev_tex_unit_map[state] = state;
2121 } else {
2122 This->texUnitMap[state] = -1;
2123 This->rev_tex_unit_map[state] = -1;
2127 /* Setup the implicit swapchain */
2128 TRACE("Creating implicit swapchain\n");
2129 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2130 if (FAILED(hr) || !swapchain) {
2131 WARN("Failed to create implicit swapchain\n");
2132 goto err_out;
2135 This->NumberOfSwapChains = 1;
2136 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2137 if(!This->swapchains) {
2138 ERR("Out of memory!\n");
2139 goto err_out;
2141 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2143 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2144 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2145 This->render_targets[0] = swapchain->backBuffer[0];
2146 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2148 else {
2149 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2150 This->render_targets[0] = swapchain->frontBuffer;
2151 This->lastActiveRenderTarget = swapchain->frontBuffer;
2153 IWineD3DSurface_AddRef(This->render_targets[0]);
2154 This->activeContext = swapchain->context[0];
2155 This->lastThread = GetCurrentThreadId();
2157 /* Depth Stencil support */
2158 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2159 if (NULL != This->stencilBufferTarget) {
2160 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2163 hr = This->shader_backend->shader_alloc_private(iface);
2164 if(FAILED(hr)) {
2165 TRACE("Shader private data couldn't be allocated\n");
2166 goto err_out;
2168 hr = This->frag_pipe->alloc_private(iface);
2169 if(FAILED(hr)) {
2170 TRACE("Fragment pipeline private data couldn't be allocated\n");
2171 goto err_out;
2173 hr = This->blitter->alloc_private(iface);
2174 if(FAILED(hr)) {
2175 TRACE("Blitter private data couldn't be allocated\n");
2176 goto err_out;
2179 /* Set up some starting GL setup */
2181 /* Setup all the devices defaults */
2182 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2183 create_dummy_textures(This);
2185 ENTER_GL();
2187 #if 0
2188 IWineD3DImpl_CheckGraphicsMemory();
2189 #endif
2191 { /* Set a default viewport */
2192 WINED3DVIEWPORT vp;
2193 vp.X = 0;
2194 vp.Y = 0;
2195 vp.Width = pPresentationParameters->BackBufferWidth;
2196 vp.Height = pPresentationParameters->BackBufferHeight;
2197 vp.MinZ = 0.0f;
2198 vp.MaxZ = 1.0f;
2199 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2202 /* Initialize the current view state */
2203 This->view_ident = 1;
2204 This->contexts[0]->last_was_rhw = 0;
2205 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2206 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2208 switch(wined3d_settings.offscreen_rendering_mode) {
2209 case ORM_FBO:
2210 case ORM_PBUFFER:
2211 This->offscreenBuffer = GL_BACK;
2212 break;
2214 case ORM_BACKBUFFER:
2216 if(This->activeContext->aux_buffers > 0) {
2217 TRACE("Using auxilliary buffer for offscreen rendering\n");
2218 This->offscreenBuffer = GL_AUX0;
2219 } else {
2220 TRACE("Using back buffer for offscreen rendering\n");
2221 This->offscreenBuffer = GL_BACK;
2226 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2227 LEAVE_GL();
2229 /* Clear the screen */
2230 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2231 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2232 0x00, 1.0, 0);
2234 This->d3d_initialized = TRUE;
2236 if(wined3d_settings.logo) {
2237 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2239 This->highest_dirty_ps_const = 0;
2240 This->highest_dirty_vs_const = 0;
2241 return WINED3D_OK;
2243 err_out:
2244 HeapFree(GetProcessHeap(), 0, This->render_targets);
2245 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2246 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2247 HeapFree(GetProcessHeap(), 0, This->swapchains);
2248 This->NumberOfSwapChains = 0;
2249 if(This->palettes) {
2250 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2251 HeapFree(GetProcessHeap(), 0, This->palettes);
2253 This->NumberOfPalettes = 0;
2254 if(swapchain) {
2255 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2257 if(This->stateBlock) {
2258 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2259 This->stateBlock = NULL;
2261 if (This->blit_priv) {
2262 This->blitter->free_private(iface);
2264 if (This->fragment_priv) {
2265 This->frag_pipe->free_private(iface);
2267 if (This->shader_priv) {
2268 This->shader_backend->shader_free_private(iface);
2270 return hr;
2273 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2275 IWineD3DSwapChainImpl *swapchain = NULL;
2276 HRESULT hr;
2278 /* Setup the implicit swapchain */
2279 TRACE("Creating implicit swapchain\n");
2280 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2281 if (FAILED(hr) || !swapchain) {
2282 WARN("Failed to create implicit swapchain\n");
2283 goto err_out;
2286 This->NumberOfSwapChains = 1;
2287 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2288 if(!This->swapchains) {
2289 ERR("Out of memory!\n");
2290 goto err_out;
2292 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2293 return WINED3D_OK;
2295 err_out:
2296 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2297 return hr;
2300 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2301 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2302 int sampler;
2303 UINT i;
2304 TRACE("(%p)\n", This);
2306 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2308 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2309 * it was created. Thus make sure a context is active for the glDelete* calls
2311 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2313 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2315 TRACE("Deleting high order patches\n");
2316 for(i = 0; i < PATCHMAP_SIZE; i++) {
2317 struct list *e1, *e2;
2318 struct WineD3DRectPatch *patch;
2319 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2320 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2321 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2325 /* Delete the palette conversion shader if it is around */
2326 if(This->paletteConversionShader) {
2327 ENTER_GL();
2328 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2329 LEAVE_GL();
2330 This->paletteConversionShader = 0;
2333 /* Delete the pbuffer context if there is any */
2334 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2336 /* Delete the mouse cursor texture */
2337 if(This->cursorTexture) {
2338 ENTER_GL();
2339 glDeleteTextures(1, &This->cursorTexture);
2340 LEAVE_GL();
2341 This->cursorTexture = 0;
2344 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2345 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2347 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2348 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2351 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2352 * private data, it might contain opengl pointers
2354 if(This->depth_blt_texture) {
2355 glDeleteTextures(1, &This->depth_blt_texture);
2356 This->depth_blt_texture = 0;
2358 if (This->depth_blt_rb) {
2359 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2360 This->depth_blt_rb = 0;
2361 This->depth_blt_rb_w = 0;
2362 This->depth_blt_rb_h = 0;
2365 /* Release the update stateblock */
2366 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2367 if(This->updateStateBlock != This->stateBlock)
2368 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2370 This->updateStateBlock = NULL;
2372 { /* because were not doing proper internal refcounts releasing the primary state block
2373 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2374 to set this->stateBlock = NULL; first */
2375 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2376 This->stateBlock = NULL;
2378 /* Release the stateblock */
2379 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2380 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2384 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2385 This->blitter->free_private(iface);
2386 This->frag_pipe->free_private(iface);
2387 This->shader_backend->shader_free_private(iface);
2389 /* Release the buffers (with sanity checks)*/
2390 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2391 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2392 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2393 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2395 This->stencilBufferTarget = NULL;
2397 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2398 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2399 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2401 TRACE("Setting rendertarget to NULL\n");
2402 This->render_targets[0] = NULL;
2404 if (This->auto_depth_stencil_buffer) {
2405 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2406 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2408 This->auto_depth_stencil_buffer = NULL;
2411 for(i=0; i < This->NumberOfSwapChains; i++) {
2412 TRACE("Releasing the implicit swapchain %d\n", i);
2413 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2414 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2418 HeapFree(GetProcessHeap(), 0, This->swapchains);
2419 This->swapchains = NULL;
2420 This->NumberOfSwapChains = 0;
2422 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2423 HeapFree(GetProcessHeap(), 0, This->palettes);
2424 This->palettes = NULL;
2425 This->NumberOfPalettes = 0;
2427 HeapFree(GetProcessHeap(), 0, This->render_targets);
2428 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2429 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2430 This->render_targets = NULL;
2431 This->fbo_color_attachments = NULL;
2432 This->draw_buffers = NULL;
2434 This->d3d_initialized = FALSE;
2435 return WINED3D_OK;
2438 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2439 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2440 unsigned int i;
2442 for(i=0; i < This->NumberOfSwapChains; i++) {
2443 TRACE("Releasing the implicit swapchain %d\n", i);
2444 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2445 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2449 HeapFree(GetProcessHeap(), 0, This->swapchains);
2450 This->swapchains = NULL;
2451 This->NumberOfSwapChains = 0;
2452 return WINED3D_OK;
2455 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2456 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2457 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2459 * There is no way to deactivate thread safety once it is enabled.
2461 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2462 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2464 /*For now just store the flag(needed in case of ddraw) */
2465 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2467 return;
2470 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2471 DEVMODEW devmode;
2472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2473 LONG ret;
2474 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2475 RECT clip_rc;
2477 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2479 /* Resize the screen even without a window:
2480 * The app could have unset it with SetCooperativeLevel, but not called
2481 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2482 * but we don't have any hwnd
2485 memset(&devmode, 0, sizeof(devmode));
2486 devmode.dmSize = sizeof(devmode);
2487 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2488 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2489 devmode.dmPelsWidth = pMode->Width;
2490 devmode.dmPelsHeight = pMode->Height;
2492 devmode.dmDisplayFrequency = pMode->RefreshRate;
2493 if (pMode->RefreshRate != 0) {
2494 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2497 /* Only change the mode if necessary */
2498 if( (This->ddraw_width == pMode->Width) &&
2499 (This->ddraw_height == pMode->Height) &&
2500 (This->ddraw_format == pMode->Format) &&
2501 (pMode->RefreshRate == 0) ) {
2502 return WINED3D_OK;
2505 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2506 if (ret != DISP_CHANGE_SUCCESSFUL) {
2507 if(devmode.dmDisplayFrequency != 0) {
2508 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2509 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2510 devmode.dmDisplayFrequency = 0;
2511 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2513 if(ret != DISP_CHANGE_SUCCESSFUL) {
2514 return WINED3DERR_NOTAVAILABLE;
2518 /* Store the new values */
2519 This->ddraw_width = pMode->Width;
2520 This->ddraw_height = pMode->Height;
2521 This->ddraw_format = pMode->Format;
2523 /* And finally clip mouse to our screen */
2524 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2525 ClipCursor(&clip_rc);
2527 return WINED3D_OK;
2530 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2532 *ppD3D= This->wineD3D;
2533 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2534 IWineD3D_AddRef(*ppD3D);
2535 return WINED3D_OK;
2538 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2541 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2542 (This->adapter->TextureRam/(1024*1024)),
2543 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2544 /* return simulated texture memory left */
2545 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2550 /*****
2551 * Get / Set FVF
2552 *****/
2553 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2556 /* Update the current state block */
2557 This->updateStateBlock->changed.fvf = TRUE;
2559 if(This->updateStateBlock->fvf == fvf) {
2560 TRACE("Application is setting the old fvf over, nothing to do\n");
2561 return WINED3D_OK;
2564 This->updateStateBlock->fvf = fvf;
2565 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2566 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2567 return WINED3D_OK;
2571 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2573 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2574 *pfvf = This->stateBlock->fvf;
2575 return WINED3D_OK;
2578 /*****
2579 * Get / Set Stream Source
2580 *****/
2581 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2582 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2583 IWineD3DVertexBuffer *oldSrc;
2585 if (StreamNumber >= MAX_STREAMS) {
2586 WARN("Stream out of range %d\n", StreamNumber);
2587 return WINED3DERR_INVALIDCALL;
2588 } else if(OffsetInBytes & 0x3) {
2589 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2590 return WINED3DERR_INVALIDCALL;
2593 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2594 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2596 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2598 if(oldSrc == pStreamData &&
2599 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2600 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2601 TRACE("Application is setting the old values over, nothing to do\n");
2602 return WINED3D_OK;
2605 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2606 if (pStreamData) {
2607 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2608 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2611 /* Handle recording of state blocks */
2612 if (This->isRecordingState) {
2613 TRACE("Recording... not performing anything\n");
2614 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2615 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2616 return WINED3D_OK;
2619 /* Need to do a getParent and pass the references up */
2620 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2621 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2622 so for now, just count internally */
2623 if (pStreamData != NULL) {
2624 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2625 InterlockedIncrement(&vbImpl->bindCount);
2626 IWineD3DVertexBuffer_AddRef(pStreamData);
2628 if (oldSrc != NULL) {
2629 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2630 IWineD3DVertexBuffer_Release(oldSrc);
2633 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2635 return WINED3D_OK;
2638 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2641 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2642 This->stateBlock->streamSource[StreamNumber],
2643 This->stateBlock->streamOffset[StreamNumber],
2644 This->stateBlock->streamStride[StreamNumber]);
2646 if (StreamNumber >= MAX_STREAMS) {
2647 WARN("Stream out of range %d\n", StreamNumber);
2648 return WINED3DERR_INVALIDCALL;
2650 *pStream = This->stateBlock->streamSource[StreamNumber];
2651 *pStride = This->stateBlock->streamStride[StreamNumber];
2652 if (pOffset) {
2653 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2656 if (*pStream != NULL) {
2657 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2659 return WINED3D_OK;
2662 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2663 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2664 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2665 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2667 /* Verify input at least in d3d9 this is invalid*/
2668 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2669 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2670 return WINED3DERR_INVALIDCALL;
2672 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2673 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2674 return WINED3DERR_INVALIDCALL;
2676 if( Divider == 0 ){
2677 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2678 return WINED3DERR_INVALIDCALL;
2681 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2682 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2684 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2685 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2687 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2688 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2689 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2692 return WINED3D_OK;
2695 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2698 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2699 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2701 TRACE("(%p) : returning %d\n", This, *Divider);
2703 return WINED3D_OK;
2706 /*****
2707 * Get / Set & Multiply Transform
2708 *****/
2709 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2712 /* Most of this routine, comments included copied from ddraw tree initially: */
2713 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2715 /* Handle recording of state blocks */
2716 if (This->isRecordingState) {
2717 TRACE("Recording... not performing anything\n");
2718 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2719 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2720 return WINED3D_OK;
2724 * If the new matrix is the same as the current one,
2725 * we cut off any further processing. this seems to be a reasonable
2726 * optimization because as was noticed, some apps (warcraft3 for example)
2727 * tend towards setting the same matrix repeatedly for some reason.
2729 * From here on we assume that the new matrix is different, wherever it matters.
2731 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2732 TRACE("The app is setting the same matrix over again\n");
2733 return WINED3D_OK;
2734 } else {
2735 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2739 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2740 where ViewMat = Camera space, WorldMat = world space.
2742 In OpenGL, camera and world space is combined into GL_MODELVIEW
2743 matrix. The Projection matrix stay projection matrix.
2746 /* Capture the times we can just ignore the change for now */
2747 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2748 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2749 /* Handled by the state manager */
2752 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2753 return WINED3D_OK;
2756 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2757 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2758 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2759 *pMatrix = This->stateBlock->transforms[State];
2760 return WINED3D_OK;
2763 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2764 WINED3DMATRIX *mat = NULL;
2765 WINED3DMATRIX temp;
2767 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2768 * below means it will be recorded in a state block change, but it
2769 * works regardless where it is recorded.
2770 * If this is found to be wrong, change to StateBlock.
2772 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2773 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2775 if (State < HIGHEST_TRANSFORMSTATE)
2777 mat = &This->updateStateBlock->transforms[State];
2778 } else {
2779 FIXME("Unhandled transform state!!\n");
2782 multiply_matrix(&temp, mat, pMatrix);
2784 /* Apply change via set transform - will reapply to eg. lights this way */
2785 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2788 /*****
2789 * Get / Set Light
2790 *****/
2791 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2792 you can reference any indexes you want as long as that number max are enabled at any
2793 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2794 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2795 but when recording, just build a chain pretty much of commands to be replayed. */
2797 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2798 float rho;
2799 PLIGHTINFOEL *object = NULL;
2800 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2801 struct list *e;
2803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2804 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2806 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2807 * the gl driver.
2809 if(!pLight) {
2810 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2811 return WINED3DERR_INVALIDCALL;
2814 switch(pLight->Type) {
2815 case WINED3DLIGHT_POINT:
2816 case WINED3DLIGHT_SPOT:
2817 case WINED3DLIGHT_PARALLELPOINT:
2818 case WINED3DLIGHT_GLSPOT:
2819 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2820 * most wanted
2822 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2823 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2824 return WINED3DERR_INVALIDCALL;
2826 break;
2828 case WINED3DLIGHT_DIRECTIONAL:
2829 /* Ignores attenuation */
2830 break;
2832 default:
2833 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2834 return WINED3DERR_INVALIDCALL;
2837 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2838 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2839 if(object->OriginalIndex == Index) break;
2840 object = NULL;
2843 if(!object) {
2844 TRACE("Adding new light\n");
2845 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2846 if(!object) {
2847 ERR("Out of memory error when allocating a light\n");
2848 return E_OUTOFMEMORY;
2850 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2851 object->glIndex = -1;
2852 object->OriginalIndex = Index;
2853 object->changed = TRUE;
2856 /* Initialize the object */
2857 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,
2858 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2859 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2860 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2861 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2862 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2863 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2865 /* Save away the information */
2866 object->OriginalParms = *pLight;
2868 switch (pLight->Type) {
2869 case WINED3DLIGHT_POINT:
2870 /* Position */
2871 object->lightPosn[0] = pLight->Position.x;
2872 object->lightPosn[1] = pLight->Position.y;
2873 object->lightPosn[2] = pLight->Position.z;
2874 object->lightPosn[3] = 1.0f;
2875 object->cutoff = 180.0f;
2876 /* FIXME: Range */
2877 break;
2879 case WINED3DLIGHT_DIRECTIONAL:
2880 /* Direction */
2881 object->lightPosn[0] = -pLight->Direction.x;
2882 object->lightPosn[1] = -pLight->Direction.y;
2883 object->lightPosn[2] = -pLight->Direction.z;
2884 object->lightPosn[3] = 0.0;
2885 object->exponent = 0.0f;
2886 object->cutoff = 180.0f;
2887 break;
2889 case WINED3DLIGHT_SPOT:
2890 /* Position */
2891 object->lightPosn[0] = pLight->Position.x;
2892 object->lightPosn[1] = pLight->Position.y;
2893 object->lightPosn[2] = pLight->Position.z;
2894 object->lightPosn[3] = 1.0;
2896 /* Direction */
2897 object->lightDirn[0] = pLight->Direction.x;
2898 object->lightDirn[1] = pLight->Direction.y;
2899 object->lightDirn[2] = pLight->Direction.z;
2900 object->lightDirn[3] = 1.0;
2903 * opengl-ish and d3d-ish spot lights use too different models for the
2904 * light "intensity" as a function of the angle towards the main light direction,
2905 * so we only can approximate very roughly.
2906 * however spot lights are rather rarely used in games (if ever used at all).
2907 * furthermore if still used, probably nobody pays attention to such details.
2909 if (pLight->Falloff == 0) {
2910 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2911 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2912 * will always be 1.0 for both of them, and we don't have to care for the
2913 * rest of the rather complex calculation
2915 object->exponent = 0;
2916 } else {
2917 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2918 if (rho < 0.0001) rho = 0.0001f;
2919 object->exponent = -0.3/log(cos(rho/2));
2921 if (object->exponent > 128.0) {
2922 object->exponent = 128.0;
2924 object->cutoff = pLight->Phi*90/M_PI;
2926 /* FIXME: Range */
2927 break;
2929 default:
2930 FIXME("Unrecognized light type %d\n", pLight->Type);
2933 /* Update the live definitions if the light is currently assigned a glIndex */
2934 if (object->glIndex != -1 && !This->isRecordingState) {
2935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2937 return WINED3D_OK;
2940 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2941 PLIGHTINFOEL *lightInfo = NULL;
2942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2943 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2944 struct list *e;
2945 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2947 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2948 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2949 if(lightInfo->OriginalIndex == Index) break;
2950 lightInfo = NULL;
2953 if (lightInfo == NULL) {
2954 TRACE("Light information requested but light not defined\n");
2955 return WINED3DERR_INVALIDCALL;
2958 *pLight = lightInfo->OriginalParms;
2959 return WINED3D_OK;
2962 /*****
2963 * Get / Set Light Enable
2964 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2965 *****/
2966 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2967 PLIGHTINFOEL *lightInfo = NULL;
2968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2969 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2970 struct list *e;
2971 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2973 /* Tests show true = 128...not clear why */
2974 Enable = Enable? 128: 0;
2976 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2977 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2978 if(lightInfo->OriginalIndex == Index) break;
2979 lightInfo = NULL;
2981 TRACE("Found light: %p\n", lightInfo);
2983 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2984 if (lightInfo == NULL) {
2986 TRACE("Light enabled requested but light not defined, so defining one!\n");
2987 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2989 /* Search for it again! Should be fairly quick as near head of list */
2990 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2991 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2992 if(lightInfo->OriginalIndex == Index) break;
2993 lightInfo = NULL;
2995 if (lightInfo == NULL) {
2996 FIXME("Adding default lights has failed dismally\n");
2997 return WINED3DERR_INVALIDCALL;
3001 lightInfo->enabledChanged = TRUE;
3002 if(!Enable) {
3003 if(lightInfo->glIndex != -1) {
3004 if(!This->isRecordingState) {
3005 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3008 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
3009 lightInfo->glIndex = -1;
3010 } else {
3011 TRACE("Light already disabled, nothing to do\n");
3013 lightInfo->enabled = FALSE;
3014 } else {
3015 lightInfo->enabled = TRUE;
3016 if (lightInfo->glIndex != -1) {
3017 /* nop */
3018 TRACE("Nothing to do as light was enabled\n");
3019 } else {
3020 int i;
3021 /* Find a free gl light */
3022 for(i = 0; i < This->maxConcurrentLights; i++) {
3023 if(This->stateBlock->activeLights[i] == NULL) {
3024 This->stateBlock->activeLights[i] = lightInfo;
3025 lightInfo->glIndex = i;
3026 break;
3029 if(lightInfo->glIndex == -1) {
3030 /* Our tests show that Windows returns D3D_OK in this situation, even with
3031 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3032 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3033 * as well for those lights.
3035 * TODO: Test how this affects rendering
3037 FIXME("Too many concurrently active lights\n");
3038 return WINED3D_OK;
3041 /* i == lightInfo->glIndex */
3042 if(!This->isRecordingState) {
3043 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3048 return WINED3D_OK;
3051 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3053 PLIGHTINFOEL *lightInfo = NULL;
3054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3055 struct list *e;
3056 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3057 TRACE("(%p) : for idx(%d)\n", This, Index);
3059 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3060 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3061 if(lightInfo->OriginalIndex == Index) break;
3062 lightInfo = NULL;
3065 if (lightInfo == NULL) {
3066 TRACE("Light enabled state requested but light not defined\n");
3067 return WINED3DERR_INVALIDCALL;
3069 /* true is 128 according to SetLightEnable */
3070 *pEnable = lightInfo->enabled ? 128 : 0;
3071 return WINED3D_OK;
3074 /*****
3075 * Get / Set Clip Planes
3076 *****/
3077 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3078 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3079 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3081 /* Validate Index */
3082 if (Index >= GL_LIMITS(clipplanes)) {
3083 TRACE("Application has requested clipplane this device doesn't support\n");
3084 return WINED3DERR_INVALIDCALL;
3087 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3089 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3090 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3091 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3092 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3093 TRACE("Application is setting old values over, nothing to do\n");
3094 return WINED3D_OK;
3097 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3098 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3099 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3100 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3102 /* Handle recording of state blocks */
3103 if (This->isRecordingState) {
3104 TRACE("Recording... not performing anything\n");
3105 return WINED3D_OK;
3108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3110 return WINED3D_OK;
3113 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3115 TRACE("(%p) : for idx %d\n", This, Index);
3117 /* Validate Index */
3118 if (Index >= GL_LIMITS(clipplanes)) {
3119 TRACE("Application has requested clipplane this device doesn't support\n");
3120 return WINED3DERR_INVALIDCALL;
3123 pPlane[0] = This->stateBlock->clipplane[Index][0];
3124 pPlane[1] = This->stateBlock->clipplane[Index][1];
3125 pPlane[2] = This->stateBlock->clipplane[Index][2];
3126 pPlane[3] = This->stateBlock->clipplane[Index][3];
3127 return WINED3D_OK;
3130 /*****
3131 * Get / Set Clip Plane Status
3132 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3133 *****/
3134 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3135 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3136 FIXME("(%p) : stub\n", This);
3137 if (NULL == pClipStatus) {
3138 return WINED3DERR_INVALIDCALL;
3140 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3141 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3142 return WINED3D_OK;
3145 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3146 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3147 FIXME("(%p) : stub\n", This);
3148 if (NULL == pClipStatus) {
3149 return WINED3DERR_INVALIDCALL;
3151 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3152 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3153 return WINED3D_OK;
3156 /*****
3157 * Get / Set Material
3158 *****/
3159 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3162 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3164 This->updateStateBlock->changed.material = TRUE;
3165 This->updateStateBlock->material = *pMaterial;
3167 /* Handle recording of state blocks */
3168 if (This->isRecordingState) {
3169 TRACE("Recording... not performing anything\n");
3170 return WINED3D_OK;
3173 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3174 return WINED3D_OK;
3177 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3178 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3179 *pMaterial = This->updateStateBlock->material;
3180 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3181 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3182 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3183 pMaterial->Ambient.b, pMaterial->Ambient.a);
3184 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3185 pMaterial->Specular.b, pMaterial->Specular.a);
3186 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3187 pMaterial->Emissive.b, pMaterial->Emissive.a);
3188 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3190 return WINED3D_OK;
3193 /*****
3194 * Get / Set Indices
3195 *****/
3196 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3197 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3198 IWineD3DIndexBuffer *oldIdxs;
3200 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3201 oldIdxs = This->updateStateBlock->pIndexData;
3203 This->updateStateBlock->changed.indices = TRUE;
3204 This->updateStateBlock->pIndexData = pIndexData;
3206 /* Handle recording of state blocks */
3207 if (This->isRecordingState) {
3208 TRACE("Recording... not performing anything\n");
3209 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3210 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3211 return WINED3D_OK;
3214 if(oldIdxs != pIndexData) {
3215 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3216 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3217 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3219 return WINED3D_OK;
3222 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3225 *ppIndexData = This->stateBlock->pIndexData;
3227 /* up ref count on ppindexdata */
3228 if (*ppIndexData) {
3229 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3230 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3231 }else{
3232 TRACE("(%p) No index data set\n", This);
3234 TRACE("Returning %p\n", *ppIndexData);
3236 return WINED3D_OK;
3239 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3240 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3241 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3242 TRACE("(%p)->(%d)\n", This, BaseIndex);
3244 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3245 TRACE("Application is setting the old value over, nothing to do\n");
3246 return WINED3D_OK;
3249 This->updateStateBlock->baseVertexIndex = BaseIndex;
3251 if (This->isRecordingState) {
3252 TRACE("Recording... not performing anything\n");
3253 return WINED3D_OK;
3255 /* The base vertex index affects the stream sources */
3256 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3257 return WINED3D_OK;
3260 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3262 TRACE("(%p) : base_index %p\n", This, base_index);
3264 *base_index = This->stateBlock->baseVertexIndex;
3266 TRACE("Returning %u\n", *base_index);
3268 return WINED3D_OK;
3271 /*****
3272 * Get / Set Viewports
3273 *****/
3274 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3275 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3277 TRACE("(%p)\n", This);
3278 This->updateStateBlock->changed.viewport = TRUE;
3279 This->updateStateBlock->viewport = *pViewport;
3281 /* Handle recording of state blocks */
3282 if (This->isRecordingState) {
3283 TRACE("Recording... not performing anything\n");
3284 return WINED3D_OK;
3287 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3288 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3290 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3291 return WINED3D_OK;
3295 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3297 TRACE("(%p)\n", This);
3298 *pViewport = This->stateBlock->viewport;
3299 return WINED3D_OK;
3302 /*****
3303 * Get / Set Render States
3304 * TODO: Verify against dx9 definitions
3305 *****/
3306 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3308 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3309 DWORD oldValue = This->stateBlock->renderState[State];
3311 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3313 This->updateStateBlock->changed.renderState[State] = TRUE;
3314 This->updateStateBlock->renderState[State] = Value;
3316 /* Handle recording of state blocks */
3317 if (This->isRecordingState) {
3318 TRACE("Recording... not performing anything\n");
3319 return WINED3D_OK;
3322 /* Compared here and not before the assignment to allow proper stateblock recording */
3323 if(Value == oldValue) {
3324 TRACE("Application is setting the old value over, nothing to do\n");
3325 } else {
3326 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3329 return WINED3D_OK;
3332 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3333 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3334 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3335 *pValue = This->stateBlock->renderState[State];
3336 return WINED3D_OK;
3339 /*****
3340 * Get / Set Sampler States
3341 * TODO: Verify against dx9 definitions
3342 *****/
3344 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3345 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3346 DWORD oldValue;
3348 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3349 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3351 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3352 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3355 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3356 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3357 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3360 * SetSampler is designed to allow for more than the standard up to 8 textures
3361 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3362 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3364 * http://developer.nvidia.com/object/General_FAQ.html#t6
3366 * There are two new settings for GForce
3367 * the sampler one:
3368 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3369 * and the texture one:
3370 * GL_MAX_TEXTURE_COORDS_ARB.
3371 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3372 ******************/
3374 oldValue = This->stateBlock->samplerState[Sampler][Type];
3375 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3376 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3378 /* Handle recording of state blocks */
3379 if (This->isRecordingState) {
3380 TRACE("Recording... not performing anything\n");
3381 return WINED3D_OK;
3384 if(oldValue == Value) {
3385 TRACE("Application is setting the old value over, nothing to do\n");
3386 return WINED3D_OK;
3389 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3391 return WINED3D_OK;
3394 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3395 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3397 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3398 This, Sampler, debug_d3dsamplerstate(Type), Type);
3400 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3401 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3404 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3405 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3406 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3408 *Value = This->stateBlock->samplerState[Sampler][Type];
3409 TRACE("(%p) : Returning %#x\n", This, *Value);
3411 return WINED3D_OK;
3414 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3417 This->updateStateBlock->changed.scissorRect = TRUE;
3418 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3419 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3420 return WINED3D_OK;
3422 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3424 if(This->isRecordingState) {
3425 TRACE("Recording... not performing anything\n");
3426 return WINED3D_OK;
3429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3431 return WINED3D_OK;
3434 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3437 *pRect = This->updateStateBlock->scissorRect;
3438 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3439 return WINED3D_OK;
3442 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3443 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3444 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3446 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3448 This->updateStateBlock->vertexDecl = pDecl;
3449 This->updateStateBlock->changed.vertexDecl = TRUE;
3451 if (This->isRecordingState) {
3452 TRACE("Recording... not performing anything\n");
3453 return WINED3D_OK;
3454 } else if(pDecl == oldDecl) {
3455 /* Checked after the assignment to allow proper stateblock recording */
3456 TRACE("Application is setting the old declaration over, nothing to do\n");
3457 return WINED3D_OK;
3460 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3461 return WINED3D_OK;
3464 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3465 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3467 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3469 *ppDecl = This->stateBlock->vertexDecl;
3470 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3471 return WINED3D_OK;
3474 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3475 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3476 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3478 This->updateStateBlock->vertexShader = pShader;
3479 This->updateStateBlock->changed.vertexShader = TRUE;
3481 if (This->isRecordingState) {
3482 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3483 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3484 TRACE("Recording... not performing anything\n");
3485 return WINED3D_OK;
3486 } else if(oldShader == pShader) {
3487 /* Checked here to allow proper stateblock recording */
3488 TRACE("App is setting the old shader over, nothing to do\n");
3489 return WINED3D_OK;
3492 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3493 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3494 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3496 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3498 return WINED3D_OK;
3501 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3504 if (NULL == ppShader) {
3505 return WINED3DERR_INVALIDCALL;
3507 *ppShader = This->stateBlock->vertexShader;
3508 if( NULL != *ppShader)
3509 IWineD3DVertexShader_AddRef(*ppShader);
3511 TRACE("(%p) : returning %p\n", This, *ppShader);
3512 return WINED3D_OK;
3515 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3516 IWineD3DDevice *iface,
3517 UINT start,
3518 CONST BOOL *srcData,
3519 UINT count) {
3521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3522 int i, cnt = min(count, MAX_CONST_B - start);
3524 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3525 iface, srcData, start, count);
3527 if (srcData == NULL || cnt < 0)
3528 return WINED3DERR_INVALIDCALL;
3530 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3531 for (i = 0; i < cnt; i++)
3532 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3534 for (i = start; i < cnt + start; ++i) {
3535 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3538 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3540 return WINED3D_OK;
3543 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3544 IWineD3DDevice *iface,
3545 UINT start,
3546 BOOL *dstData,
3547 UINT count) {
3549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3550 int cnt = min(count, MAX_CONST_B - start);
3552 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3553 iface, dstData, start, count);
3555 if (dstData == NULL || cnt < 0)
3556 return WINED3DERR_INVALIDCALL;
3558 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3559 return WINED3D_OK;
3562 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3563 IWineD3DDevice *iface,
3564 UINT start,
3565 CONST int *srcData,
3566 UINT count) {
3568 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3569 int i, cnt = min(count, MAX_CONST_I - start);
3571 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3572 iface, srcData, start, count);
3574 if (srcData == NULL || cnt < 0)
3575 return WINED3DERR_INVALIDCALL;
3577 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3578 for (i = 0; i < cnt; i++)
3579 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3580 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3582 for (i = start; i < cnt + start; ++i) {
3583 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3586 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3588 return WINED3D_OK;
3591 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3592 IWineD3DDevice *iface,
3593 UINT start,
3594 int *dstData,
3595 UINT count) {
3597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3598 int cnt = min(count, MAX_CONST_I - start);
3600 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3601 iface, dstData, start, count);
3603 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3604 return WINED3DERR_INVALIDCALL;
3606 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3607 return WINED3D_OK;
3610 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3611 IWineD3DDevice *iface,
3612 UINT start,
3613 CONST float *srcData,
3614 UINT count) {
3616 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3617 int i;
3619 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3620 iface, srcData, start, count);
3622 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3623 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3624 return WINED3DERR_INVALIDCALL;
3626 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3627 if(TRACE_ON(d3d)) {
3628 for (i = 0; i < count; i++)
3629 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3630 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3633 for (i = start; i < count + start; ++i) {
3634 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3635 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3636 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3637 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3638 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3640 ptr->idx[ptr->count++] = i;
3641 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3645 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3647 return WINED3D_OK;
3650 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3651 IWineD3DDevice *iface,
3652 UINT start,
3653 CONST float *srcData,
3654 UINT count) {
3656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3657 int i;
3659 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3660 iface, srcData, start, count);
3662 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3663 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3664 return WINED3DERR_INVALIDCALL;
3666 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3667 if(TRACE_ON(d3d)) {
3668 for (i = 0; i < count; i++)
3669 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3670 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3673 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3674 * context. On a context switch the old context will be fully dirtified
3676 memset(This->activeContext->vshader_const_dirty + start, 1,
3677 sizeof(*This->activeContext->vshader_const_dirty) * count);
3678 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3680 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3682 return WINED3D_OK;
3685 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3686 IWineD3DDevice *iface,
3687 UINT start,
3688 float *dstData,
3689 UINT count) {
3691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3692 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3694 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3695 iface, dstData, start, count);
3697 if (dstData == NULL || cnt < 0)
3698 return WINED3DERR_INVALIDCALL;
3700 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3701 return WINED3D_OK;
3704 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3705 DWORD i;
3706 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3707 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3711 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3712 int i = This->rev_tex_unit_map[unit];
3713 int j = This->texUnitMap[stage];
3715 This->texUnitMap[stage] = unit;
3716 if (i != -1 && i != stage) {
3717 This->texUnitMap[i] = -1;
3720 This->rev_tex_unit_map[unit] = stage;
3721 if (j != -1 && j != unit) {
3722 This->rev_tex_unit_map[j] = -1;
3726 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3727 int i;
3729 for (i = 0; i < MAX_TEXTURES; ++i) {
3730 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3731 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3732 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3733 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3734 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3735 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3736 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3737 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3739 if (color_op == WINED3DTOP_DISABLE) {
3740 /* Not used, and disable higher stages */
3741 while (i < MAX_TEXTURES) {
3742 This->fixed_function_usage_map[i] = FALSE;
3743 ++i;
3745 break;
3748 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3749 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3750 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3751 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3752 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3753 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3754 This->fixed_function_usage_map[i] = TRUE;
3755 } else {
3756 This->fixed_function_usage_map[i] = FALSE;
3759 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3760 This->fixed_function_usage_map[i+1] = TRUE;
3765 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3766 int i, tex;
3768 device_update_fixed_function_usage_map(This);
3770 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3771 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3772 if (!This->fixed_function_usage_map[i]) continue;
3774 if (This->texUnitMap[i] != i) {
3775 device_map_stage(This, i, i);
3776 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3777 markTextureStagesDirty(This, i);
3780 return;
3783 /* Now work out the mapping */
3784 tex = 0;
3785 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3786 if (!This->fixed_function_usage_map[i]) continue;
3788 if (This->texUnitMap[i] != tex) {
3789 device_map_stage(This, i, tex);
3790 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3791 markTextureStagesDirty(This, i);
3794 ++tex;
3798 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3799 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3800 int i;
3802 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3803 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3804 device_map_stage(This, i, i);
3805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3806 if (i < MAX_TEXTURES) {
3807 markTextureStagesDirty(This, i);
3813 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3814 int current_mapping = This->rev_tex_unit_map[unit];
3816 if (current_mapping == -1) {
3817 /* Not currently used */
3818 return TRUE;
3821 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3822 /* Used by a fragment sampler */
3824 if (!pshader_sampler_tokens) {
3825 /* No pixel shader, check fixed function */
3826 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3829 /* Pixel shader, check the shader's sampler map */
3830 return !pshader_sampler_tokens[current_mapping];
3833 /* Used by a vertex sampler */
3834 return !vshader_sampler_tokens[current_mapping];
3837 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3838 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3839 DWORD *pshader_sampler_tokens = NULL;
3840 int start = GL_LIMITS(combined_samplers) - 1;
3841 int i;
3843 if (ps) {
3844 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3846 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3847 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3848 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3851 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3852 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3853 if (vshader_sampler_tokens[i]) {
3854 if (This->texUnitMap[vsampler_idx] != -1) {
3855 /* Already mapped somewhere */
3856 continue;
3859 while (start >= 0) {
3860 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3861 device_map_stage(This, vsampler_idx, start);
3862 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3864 --start;
3865 break;
3868 --start;
3874 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3875 BOOL vs = use_vs(This);
3876 BOOL ps = use_ps(This);
3878 * Rules are:
3879 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3880 * that would be really messy and require shader recompilation
3881 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3882 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3884 if (ps) {
3885 device_map_psamplers(This);
3886 } else {
3887 device_map_fixed_function_samplers(This);
3890 if (vs) {
3891 device_map_vsamplers(This, ps);
3895 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3896 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3897 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3898 This->updateStateBlock->pixelShader = pShader;
3899 This->updateStateBlock->changed.pixelShader = TRUE;
3901 /* Handle recording of state blocks */
3902 if (This->isRecordingState) {
3903 TRACE("Recording... not performing anything\n");
3906 if (This->isRecordingState) {
3907 TRACE("Recording... not performing anything\n");
3908 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3909 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3910 return WINED3D_OK;
3913 if(pShader == oldShader) {
3914 TRACE("App is setting the old pixel shader over, nothing to do\n");
3915 return WINED3D_OK;
3918 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3919 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3921 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3922 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3924 return WINED3D_OK;
3927 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3928 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3930 if (NULL == ppShader) {
3931 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3932 return WINED3DERR_INVALIDCALL;
3935 *ppShader = This->stateBlock->pixelShader;
3936 if (NULL != *ppShader) {
3937 IWineD3DPixelShader_AddRef(*ppShader);
3939 TRACE("(%p) : returning %p\n", This, *ppShader);
3940 return WINED3D_OK;
3943 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3944 IWineD3DDevice *iface,
3945 UINT start,
3946 CONST BOOL *srcData,
3947 UINT count) {
3949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3950 int i, cnt = min(count, MAX_CONST_B - start);
3952 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3953 iface, srcData, start, count);
3955 if (srcData == NULL || cnt < 0)
3956 return WINED3DERR_INVALIDCALL;
3958 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3959 for (i = 0; i < cnt; i++)
3960 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3962 for (i = start; i < cnt + start; ++i) {
3963 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3968 return WINED3D_OK;
3971 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3972 IWineD3DDevice *iface,
3973 UINT start,
3974 BOOL *dstData,
3975 UINT count) {
3977 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3978 int cnt = min(count, MAX_CONST_B - start);
3980 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3981 iface, dstData, start, count);
3983 if (dstData == NULL || cnt < 0)
3984 return WINED3DERR_INVALIDCALL;
3986 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3987 return WINED3D_OK;
3990 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3991 IWineD3DDevice *iface,
3992 UINT start,
3993 CONST int *srcData,
3994 UINT count) {
3996 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3997 int i, cnt = min(count, MAX_CONST_I - start);
3999 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4000 iface, srcData, start, count);
4002 if (srcData == NULL || cnt < 0)
4003 return WINED3DERR_INVALIDCALL;
4005 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4006 for (i = 0; i < cnt; i++)
4007 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4008 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4010 for (i = start; i < cnt + start; ++i) {
4011 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4014 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4016 return WINED3D_OK;
4019 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4020 IWineD3DDevice *iface,
4021 UINT start,
4022 int *dstData,
4023 UINT count) {
4025 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4026 int cnt = min(count, MAX_CONST_I - start);
4028 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4029 iface, dstData, start, count);
4031 if (dstData == NULL || cnt < 0)
4032 return WINED3DERR_INVALIDCALL;
4034 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4035 return WINED3D_OK;
4038 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4039 IWineD3DDevice *iface,
4040 UINT start,
4041 CONST float *srcData,
4042 UINT count) {
4044 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4045 int i;
4047 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4048 iface, srcData, start, count);
4050 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4051 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4052 return WINED3DERR_INVALIDCALL;
4054 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4055 if(TRACE_ON(d3d)) {
4056 for (i = 0; i < count; i++)
4057 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4058 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4061 for (i = start; i < count + start; ++i) {
4062 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4063 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4064 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4065 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4066 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4068 ptr->idx[ptr->count++] = i;
4069 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4073 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4075 return WINED3D_OK;
4078 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4079 IWineD3DDevice *iface,
4080 UINT start,
4081 CONST float *srcData,
4082 UINT count) {
4084 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4085 int i;
4087 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4088 iface, srcData, start, count);
4090 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4091 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4092 return WINED3DERR_INVALIDCALL;
4094 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4095 if(TRACE_ON(d3d)) {
4096 for (i = 0; i < count; i++)
4097 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4098 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4101 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4102 * context. On a context switch the old context will be fully dirtified
4104 memset(This->activeContext->pshader_const_dirty + start, 1,
4105 sizeof(*This->activeContext->pshader_const_dirty) * count);
4106 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4108 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4110 return WINED3D_OK;
4113 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4114 IWineD3DDevice *iface,
4115 UINT start,
4116 float *dstData,
4117 UINT count) {
4119 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4120 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4122 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4123 iface, dstData, start, count);
4125 if (dstData == NULL || cnt < 0)
4126 return WINED3DERR_INVALIDCALL;
4128 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4129 return WINED3D_OK;
4132 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4133 static HRESULT
4134 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4135 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4136 unsigned int i;
4137 DWORD DestFVF = dest->fvf;
4138 WINED3DVIEWPORT vp;
4139 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4140 BOOL doClip;
4141 int numTextures;
4143 if (lpStrideData->u.s.normal.lpData) {
4144 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4147 if (lpStrideData->u.s.position.lpData == NULL) {
4148 ERR("Source has no position mask\n");
4149 return WINED3DERR_INVALIDCALL;
4152 /* We might access VBOs from this code, so hold the lock */
4153 ENTER_GL();
4155 if (dest->resource.allocatedMemory == NULL) {
4156 /* This may happen if we do direct locking into a vbo. Unlikely,
4157 * but theoretically possible(ddraw processvertices test)
4159 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4160 if(!dest->resource.allocatedMemory) {
4161 LEAVE_GL();
4162 ERR("Out of memory\n");
4163 return E_OUTOFMEMORY;
4165 if(dest->vbo) {
4166 void *src;
4167 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4168 checkGLcall("glBindBufferARB");
4169 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4170 if(src) {
4171 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4173 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4174 checkGLcall("glUnmapBufferARB");
4178 /* Get a pointer into the destination vbo(create one if none exists) and
4179 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4181 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4182 dest->Flags |= VBFLAG_CREATEVBO;
4183 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4186 if(dest->vbo) {
4187 unsigned char extrabytes = 0;
4188 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4189 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4190 * this may write 4 extra bytes beyond the area that should be written
4192 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4193 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4194 if(!dest_conv_addr) {
4195 ERR("Out of memory\n");
4196 /* Continue without storing converted vertices */
4198 dest_conv = dest_conv_addr;
4201 /* Should I clip?
4202 * a) WINED3DRS_CLIPPING is enabled
4203 * b) WINED3DVOP_CLIP is passed
4205 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4206 static BOOL warned = FALSE;
4208 * The clipping code is not quite correct. Some things need
4209 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4210 * so disable clipping for now.
4211 * (The graphics in Half-Life are broken, and my processvertices
4212 * test crashes with IDirect3DDevice3)
4213 doClip = TRUE;
4215 doClip = FALSE;
4216 if(!warned) {
4217 warned = TRUE;
4218 FIXME("Clipping is broken and disabled for now\n");
4220 } else doClip = FALSE;
4221 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4223 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4224 WINED3DTS_VIEW,
4225 &view_mat);
4226 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4227 WINED3DTS_PROJECTION,
4228 &proj_mat);
4229 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4230 WINED3DTS_WORLDMATRIX(0),
4231 &world_mat);
4233 TRACE("View mat:\n");
4234 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);
4235 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);
4236 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);
4237 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);
4239 TRACE("Proj mat:\n");
4240 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);
4241 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);
4242 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);
4243 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);
4245 TRACE("World mat:\n");
4246 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);
4247 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);
4248 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);
4249 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);
4251 /* Get the viewport */
4252 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4253 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4254 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4256 multiply_matrix(&mat,&view_mat,&world_mat);
4257 multiply_matrix(&mat,&proj_mat,&mat);
4259 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4261 for (i = 0; i < dwCount; i+= 1) {
4262 unsigned int tex_index;
4264 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4265 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4266 /* The position first */
4267 float *p =
4268 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4269 float x, y, z, rhw;
4270 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4272 /* Multiplication with world, view and projection matrix */
4273 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);
4274 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);
4275 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);
4276 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);
4278 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4280 /* WARNING: The following things are taken from d3d7 and were not yet checked
4281 * against d3d8 or d3d9!
4284 /* Clipping conditions: From msdn
4286 * A vertex is clipped if it does not match the following requirements
4287 * -rhw < x <= rhw
4288 * -rhw < y <= rhw
4289 * 0 < z <= rhw
4290 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4292 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4293 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4297 if( !doClip ||
4298 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4299 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4300 ( rhw > eps ) ) ) {
4302 /* "Normal" viewport transformation (not clipped)
4303 * 1) The values are divided by rhw
4304 * 2) The y axis is negative, so multiply it with -1
4305 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4306 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4307 * 4) Multiply x with Width/2 and add Width/2
4308 * 5) The same for the height
4309 * 6) Add the viewpoint X and Y to the 2D coordinates and
4310 * The minimum Z value to z
4311 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4313 * Well, basically it's simply a linear transformation into viewport
4314 * coordinates
4317 x /= rhw;
4318 y /= rhw;
4319 z /= rhw;
4321 y *= -1;
4323 x *= vp.Width / 2;
4324 y *= vp.Height / 2;
4325 z *= vp.MaxZ - vp.MinZ;
4327 x += vp.Width / 2 + vp.X;
4328 y += vp.Height / 2 + vp.Y;
4329 z += vp.MinZ;
4331 rhw = 1 / rhw;
4332 } else {
4333 /* That vertex got clipped
4334 * Contrary to OpenGL it is not dropped completely, it just
4335 * undergoes a different calculation.
4337 TRACE("Vertex got clipped\n");
4338 x += rhw;
4339 y += rhw;
4341 x /= 2;
4342 y /= 2;
4344 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4345 * outside of the main vertex buffer memory. That needs some more
4346 * investigation...
4350 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4353 ( (float *) dest_ptr)[0] = x;
4354 ( (float *) dest_ptr)[1] = y;
4355 ( (float *) dest_ptr)[2] = z;
4356 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4358 dest_ptr += 3 * sizeof(float);
4360 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4361 dest_ptr += sizeof(float);
4364 if(dest_conv) {
4365 float w = 1 / rhw;
4366 ( (float *) dest_conv)[0] = x * w;
4367 ( (float *) dest_conv)[1] = y * w;
4368 ( (float *) dest_conv)[2] = z * w;
4369 ( (float *) dest_conv)[3] = w;
4371 dest_conv += 3 * sizeof(float);
4373 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4374 dest_conv += sizeof(float);
4378 if (DestFVF & WINED3DFVF_PSIZE) {
4379 dest_ptr += sizeof(DWORD);
4380 if(dest_conv) dest_conv += sizeof(DWORD);
4382 if (DestFVF & WINED3DFVF_NORMAL) {
4383 float *normal =
4384 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4385 /* AFAIK this should go into the lighting information */
4386 FIXME("Didn't expect the destination to have a normal\n");
4387 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4388 if(dest_conv) {
4389 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4393 if (DestFVF & WINED3DFVF_DIFFUSE) {
4394 DWORD *color_d =
4395 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4396 if(!color_d) {
4397 static BOOL warned = FALSE;
4399 if(!warned) {
4400 ERR("No diffuse color in source, but destination has one\n");
4401 warned = TRUE;
4404 *( (DWORD *) dest_ptr) = 0xffffffff;
4405 dest_ptr += sizeof(DWORD);
4407 if(dest_conv) {
4408 *( (DWORD *) dest_conv) = 0xffffffff;
4409 dest_conv += sizeof(DWORD);
4412 else {
4413 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4414 if(dest_conv) {
4415 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4416 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4417 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4418 dest_conv += sizeof(DWORD);
4423 if (DestFVF & WINED3DFVF_SPECULAR) {
4424 /* What's the color value in the feedback buffer? */
4425 DWORD *color_s =
4426 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4427 if(!color_s) {
4428 static BOOL warned = FALSE;
4430 if(!warned) {
4431 ERR("No specular color in source, but destination has one\n");
4432 warned = TRUE;
4435 *( (DWORD *) dest_ptr) = 0xFF000000;
4436 dest_ptr += sizeof(DWORD);
4438 if(dest_conv) {
4439 *( (DWORD *) dest_conv) = 0xFF000000;
4440 dest_conv += sizeof(DWORD);
4443 else {
4444 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4445 if(dest_conv) {
4446 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4447 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4448 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4449 dest_conv += sizeof(DWORD);
4454 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4455 float *tex_coord =
4456 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4457 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4458 if(!tex_coord) {
4459 ERR("No source texture, but destination requests one\n");
4460 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4461 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4463 else {
4464 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4465 if(dest_conv) {
4466 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4472 if(dest_conv) {
4473 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4474 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4475 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4476 dwCount * get_flexible_vertex_size(DestFVF),
4477 dest_conv_addr));
4478 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4479 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4482 LEAVE_GL();
4484 return WINED3D_OK;
4486 #undef copy_and_next
4488 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4489 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4490 WineDirect3DVertexStridedData strided;
4491 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4492 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4494 if(pVertexDecl) {
4495 ERR("Output vertex declaration not implemented yet\n");
4498 /* Need any context to write to the vbo. */
4499 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4501 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4502 * control the streamIsUP flag, thus restore it afterwards.
4504 This->stateBlock->streamIsUP = FALSE;
4505 memset(&strided, 0, sizeof(strided));
4506 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4507 This->stateBlock->streamIsUP = streamWasUP;
4509 if(vbo || SrcStartIndex) {
4510 unsigned int i;
4511 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4512 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4514 * Also get the start index in, but only loop over all elements if there's something to add at all.
4516 #define FIXSRC(type) \
4517 if(strided.u.s.type.VBO) { \
4518 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4519 strided.u.s.type.VBO = 0; \
4520 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4521 ENTER_GL(); \
4522 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4523 vb->vbo = 0; \
4524 LEAVE_GL(); \
4526 if(strided.u.s.type.lpData) { \
4527 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4529 FIXSRC(position);
4530 FIXSRC(blendWeights);
4531 FIXSRC(blendMatrixIndices);
4532 FIXSRC(normal);
4533 FIXSRC(pSize);
4534 FIXSRC(diffuse);
4535 FIXSRC(specular);
4536 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4537 FIXSRC(texCoords[i]);
4539 FIXSRC(position2);
4540 FIXSRC(normal2);
4541 FIXSRC(tangent);
4542 FIXSRC(binormal);
4543 FIXSRC(tessFactor);
4544 FIXSRC(fog);
4545 FIXSRC(depth);
4546 FIXSRC(sample);
4547 #undef FIXSRC
4550 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4553 /*****
4554 * Get / Set Texture Stage States
4555 * TODO: Verify against dx9 definitions
4556 *****/
4557 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4558 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4559 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4561 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4563 if (Stage >= MAX_TEXTURES) {
4564 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4565 return WINED3D_OK;
4568 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4569 This->updateStateBlock->textureState[Stage][Type] = Value;
4571 if (This->isRecordingState) {
4572 TRACE("Recording... not performing anything\n");
4573 return WINED3D_OK;
4576 /* Checked after the assignments to allow proper stateblock recording */
4577 if(oldValue == Value) {
4578 TRACE("App is setting the old value over, nothing to do\n");
4579 return WINED3D_OK;
4582 if(Stage > This->stateBlock->lowest_disabled_stage &&
4583 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4584 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4585 * Changes in other states are important on disabled stages too
4587 return WINED3D_OK;
4590 if(Type == WINED3DTSS_COLOROP) {
4591 int i;
4593 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4594 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4595 * they have to be disabled
4597 * The current stage is dirtified below.
4599 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4600 TRACE("Additionally dirtifying stage %d\n", i);
4601 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4603 This->stateBlock->lowest_disabled_stage = Stage;
4604 TRACE("New lowest disabled: %d\n", Stage);
4605 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4606 /* Previously disabled stage enabled. Stages above it may need enabling
4607 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4608 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4610 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4613 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4614 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4615 break;
4617 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4618 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4620 This->stateBlock->lowest_disabled_stage = i;
4621 TRACE("New lowest disabled: %d\n", i);
4623 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4624 /* TODO: Built a stage -> texture unit mapping for register combiners */
4628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4630 return WINED3D_OK;
4633 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4635 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4636 *pValue = This->updateStateBlock->textureState[Stage][Type];
4637 return WINED3D_OK;
4640 /*****
4641 * Get / Set Texture
4642 *****/
4643 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4644 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4645 IWineD3DBaseTexture *oldTexture;
4647 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4649 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4650 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4653 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4654 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4655 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4658 oldTexture = This->updateStateBlock->textures[Stage];
4660 if(pTexture != NULL) {
4661 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4663 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4664 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4665 return WINED3DERR_INVALIDCALL;
4667 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4670 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4671 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4673 This->updateStateBlock->changed.textures[Stage] = TRUE;
4674 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4675 This->updateStateBlock->textures[Stage] = pTexture;
4677 /* Handle recording of state blocks */
4678 if (This->isRecordingState) {
4679 TRACE("Recording... not performing anything\n");
4680 return WINED3D_OK;
4683 if(oldTexture == pTexture) {
4684 TRACE("App is setting the same texture again, nothing to do\n");
4685 return WINED3D_OK;
4688 /** NOTE: MSDN says that setTexture increases the reference count,
4689 * and that the application must set the texture back to null (or have a leaky application),
4690 * This means we should pass the refcount up to the parent
4691 *******************************/
4692 if (NULL != This->updateStateBlock->textures[Stage]) {
4693 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4694 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4696 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4697 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4698 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4699 * so the COLOROP and ALPHAOP have to be dirtified.
4701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4704 if(bindCount == 1) {
4705 new->baseTexture.sampler = Stage;
4707 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4711 if (NULL != oldTexture) {
4712 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4713 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4715 IWineD3DBaseTexture_Release(oldTexture);
4716 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4717 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4718 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4721 if(bindCount && old->baseTexture.sampler == Stage) {
4722 int i;
4723 /* Have to do a search for the other sampler(s) where the texture is bound to
4724 * Shouldn't happen as long as apps bind a texture only to one stage
4726 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4727 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4728 if(This->updateStateBlock->textures[i] == oldTexture) {
4729 old->baseTexture.sampler = i;
4730 break;
4736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4738 return WINED3D_OK;
4741 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4742 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4744 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4746 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4747 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4750 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4751 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4752 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4755 *ppTexture=This->stateBlock->textures[Stage];
4756 if (*ppTexture)
4757 IWineD3DBaseTexture_AddRef(*ppTexture);
4759 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4761 return WINED3D_OK;
4764 /*****
4765 * Get Back Buffer
4766 *****/
4767 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4768 IWineD3DSurface **ppBackBuffer) {
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4770 IWineD3DSwapChain *swapChain;
4771 HRESULT hr;
4773 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4775 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4776 if (hr == WINED3D_OK) {
4777 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4778 IWineD3DSwapChain_Release(swapChain);
4779 } else {
4780 *ppBackBuffer = NULL;
4782 return hr;
4785 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4787 WARN("(%p) : stub, calling idirect3d for now\n", This);
4788 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4791 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4792 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4793 IWineD3DSwapChain *swapChain;
4794 HRESULT hr;
4796 if(iSwapChain > 0) {
4797 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4798 if (hr == WINED3D_OK) {
4799 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4800 IWineD3DSwapChain_Release(swapChain);
4801 } else {
4802 FIXME("(%p) Error getting display mode\n", This);
4804 } else {
4805 /* Don't read the real display mode,
4806 but return the stored mode instead. X11 can't change the color
4807 depth, and some apps are pretty angry if they SetDisplayMode from
4808 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4810 Also don't relay to the swapchain because with ddraw it's possible
4811 that there isn't a swapchain at all */
4812 pMode->Width = This->ddraw_width;
4813 pMode->Height = This->ddraw_height;
4814 pMode->Format = This->ddraw_format;
4815 pMode->RefreshRate = 0;
4816 hr = WINED3D_OK;
4819 return hr;
4822 /*****
4823 * Stateblock related functions
4824 *****/
4826 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4827 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4828 IWineD3DStateBlockImpl *object;
4829 HRESULT temp_result;
4830 int i;
4832 TRACE("(%p)\n", This);
4834 if (This->isRecordingState) {
4835 return WINED3DERR_INVALIDCALL;
4838 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4839 if (NULL == object ) {
4840 FIXME("(%p)Error allocating memory for stateblock\n", This);
4841 return E_OUTOFMEMORY;
4843 TRACE("(%p) created object %p\n", This, object);
4844 object->wineD3DDevice= This;
4845 /** FIXME: object->parent = parent; **/
4846 object->parent = NULL;
4847 object->blockType = WINED3DSBT_RECORDED;
4848 object->ref = 1;
4849 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4851 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4852 list_init(&object->lightMap[i]);
4855 temp_result = allocate_shader_constants(object);
4856 if (WINED3D_OK != temp_result)
4857 return temp_result;
4859 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4860 This->updateStateBlock = object;
4861 This->isRecordingState = TRUE;
4863 TRACE("(%p) recording stateblock %p\n",This , object);
4864 return WINED3D_OK;
4867 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4868 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4869 unsigned int i, j;
4870 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4872 if (!This->isRecordingState) {
4873 FIXME("(%p) not recording! returning error\n", This);
4874 *ppStateBlock = NULL;
4875 return WINED3DERR_INVALIDCALL;
4878 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4879 if(object->changed.renderState[i]) {
4880 object->contained_render_states[object->num_contained_render_states] = i;
4881 object->num_contained_render_states++;
4884 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4885 if(object->changed.transform[i]) {
4886 object->contained_transform_states[object->num_contained_transform_states] = i;
4887 object->num_contained_transform_states++;
4890 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4891 if(object->changed.vertexShaderConstantsF[i]) {
4892 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4893 object->num_contained_vs_consts_f++;
4896 for(i = 0; i < MAX_CONST_I; i++) {
4897 if(object->changed.vertexShaderConstantsI[i]) {
4898 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4899 object->num_contained_vs_consts_i++;
4902 for(i = 0; i < MAX_CONST_B; i++) {
4903 if(object->changed.vertexShaderConstantsB[i]) {
4904 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4905 object->num_contained_vs_consts_b++;
4908 for(i = 0; i < MAX_CONST_I; i++) {
4909 if(object->changed.pixelShaderConstantsI[i]) {
4910 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4911 object->num_contained_ps_consts_i++;
4914 for(i = 0; i < MAX_CONST_B; i++) {
4915 if(object->changed.pixelShaderConstantsB[i]) {
4916 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4917 object->num_contained_ps_consts_b++;
4920 for(i = 0; i < MAX_TEXTURES; i++) {
4921 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4922 if(object->changed.textureState[i][j]) {
4923 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4924 object->contained_tss_states[object->num_contained_tss_states].state = j;
4925 object->num_contained_tss_states++;
4929 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4930 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4931 if(object->changed.samplerState[i][j]) {
4932 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4933 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4934 object->num_contained_sampler_states++;
4939 *ppStateBlock = (IWineD3DStateBlock*) object;
4940 This->isRecordingState = FALSE;
4941 This->updateStateBlock = This->stateBlock;
4942 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4943 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4944 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4945 return WINED3D_OK;
4948 /*****
4949 * Scene related functions
4950 *****/
4951 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4952 /* At the moment we have no need for any functionality at the beginning
4953 of a scene */
4954 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4955 TRACE("(%p)\n", This);
4957 if(This->inScene) {
4958 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4959 return WINED3DERR_INVALIDCALL;
4961 This->inScene = TRUE;
4962 return WINED3D_OK;
4965 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4966 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4967 TRACE("(%p)\n", This);
4969 if(!This->inScene) {
4970 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4971 return WINED3DERR_INVALIDCALL;
4974 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4975 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4976 glFlush();
4977 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4978 * fails
4981 This->inScene = FALSE;
4982 return WINED3D_OK;
4985 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4986 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4987 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4988 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4989 IWineD3DSwapChain *swapChain = NULL;
4990 int i;
4991 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4993 TRACE("(%p) Presenting the frame\n", This);
4995 for(i = 0 ; i < swapchains ; i ++) {
4997 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4998 TRACE("presentinng chain %d, %p\n", i, swapChain);
4999 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5000 IWineD3DSwapChain_Release(swapChain);
5003 return WINED3D_OK;
5006 /* Not called from the VTable (internal subroutine) */
5007 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5008 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5009 float Z, DWORD Stencil) {
5010 GLbitfield glMask = 0;
5011 unsigned int i;
5012 WINED3DRECT curRect;
5013 RECT vp_rect;
5014 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5015 UINT drawable_width, drawable_height;
5016 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5018 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5019 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5020 * for the cleared parts, and the untouched parts.
5022 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5023 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5024 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5025 * checking all this if the dest surface is in the drawable anyway.
5027 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5028 while(1) {
5029 if(vp->X != 0 || vp->Y != 0 ||
5030 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5031 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5032 break;
5034 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5035 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5036 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5037 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5038 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5039 break;
5041 if(Count > 0 && pRects && (
5042 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5043 pRects[0].x2 < target->currentDesc.Width ||
5044 pRects[0].y2 < target->currentDesc.Height)) {
5045 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5046 break;
5048 break;
5052 target->get_drawable_size(target, &drawable_width, &drawable_height);
5054 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5055 ENTER_GL();
5057 /* Only set the values up once, as they are not changing */
5058 if (Flags & WINED3DCLEAR_STENCIL) {
5059 glClearStencil(Stencil);
5060 checkGLcall("glClearStencil");
5061 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5062 glStencilMask(0xFFFFFFFF);
5065 if (Flags & WINED3DCLEAR_ZBUFFER) {
5066 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5067 glDepthMask(GL_TRUE);
5068 glClearDepth(Z);
5069 checkGLcall("glClearDepth");
5070 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5071 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5073 if (vp->X != 0 || vp->Y != 0 ||
5074 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5075 surface_load_ds_location(This->stencilBufferTarget, location);
5077 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5078 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5079 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5080 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5081 surface_load_ds_location(This->stencilBufferTarget, location);
5083 else if (Count > 0 && pRects && (
5084 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5085 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5086 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5087 surface_load_ds_location(This->stencilBufferTarget, location);
5091 if (Flags & WINED3DCLEAR_TARGET) {
5092 TRACE("Clearing screen with glClear to color %x\n", Color);
5093 glClearColor(D3DCOLOR_R(Color),
5094 D3DCOLOR_G(Color),
5095 D3DCOLOR_B(Color),
5096 D3DCOLOR_A(Color));
5097 checkGLcall("glClearColor");
5099 /* Clear ALL colors! */
5100 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5101 glMask = glMask | GL_COLOR_BUFFER_BIT;
5104 vp_rect.left = vp->X;
5105 vp_rect.top = vp->Y;
5106 vp_rect.right = vp->X + vp->Width;
5107 vp_rect.bottom = vp->Y + vp->Height;
5108 if (!(Count > 0 && pRects)) {
5109 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5110 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5112 if(This->render_offscreen) {
5113 glScissor(vp_rect.left, vp_rect.top,
5114 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5115 } else {
5116 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5117 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5119 checkGLcall("glScissor");
5120 glClear(glMask);
5121 checkGLcall("glClear");
5122 } else {
5123 /* Now process each rect in turn */
5124 for (i = 0; i < Count; i++) {
5125 /* Note gl uses lower left, width/height */
5126 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5127 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5128 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5130 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5131 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5132 curRect.x1, (target->currentDesc.Height - curRect.y2),
5133 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5135 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5136 * The rectangle is not cleared, no error is returned, but further rectanlges are
5137 * still cleared if they are valid
5139 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5140 TRACE("Rectangle with negative dimensions, ignoring\n");
5141 continue;
5144 if(This->render_offscreen) {
5145 glScissor(curRect.x1, curRect.y1,
5146 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5147 } else {
5148 glScissor(curRect.x1, drawable_height - curRect.y2,
5149 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5151 checkGLcall("glScissor");
5153 glClear(glMask);
5154 checkGLcall("glClear");
5158 /* Restore the old values (why..?) */
5159 if (Flags & WINED3DCLEAR_STENCIL) {
5160 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5162 if (Flags & WINED3DCLEAR_TARGET) {
5163 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5164 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5165 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5166 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5167 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5169 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5170 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5172 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5173 /* TODO: Move the fbo logic into ModifyLocation() */
5174 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5175 target->Flags |= SFLAG_INTEXTURE;
5178 if (Flags & WINED3DCLEAR_ZBUFFER) {
5179 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5180 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5181 surface_modify_ds_location(This->stencilBufferTarget, location);
5184 LEAVE_GL();
5186 return WINED3D_OK;
5189 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5190 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5192 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5194 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5195 Count, pRects, Flags, Color, Z, Stencil);
5197 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5198 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5199 /* TODO: What about depth stencil buffers without stencil bits? */
5200 return WINED3DERR_INVALIDCALL;
5203 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5206 /*****
5207 * Drawing functions
5208 *****/
5209 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5210 UINT PrimitiveCount) {
5212 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5214 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5215 debug_d3dprimitivetype(PrimitiveType),
5216 StartVertex, PrimitiveCount);
5218 if(!This->stateBlock->vertexDecl) {
5219 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5220 return WINED3DERR_INVALIDCALL;
5223 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5224 if(This->stateBlock->streamIsUP) {
5225 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5226 This->stateBlock->streamIsUP = FALSE;
5229 if(This->stateBlock->loadBaseVertexIndex != 0) {
5230 This->stateBlock->loadBaseVertexIndex = 0;
5231 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5233 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5234 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5235 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5236 return WINED3D_OK;
5239 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5240 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5241 WINED3DPRIMITIVETYPE PrimitiveType,
5242 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5244 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5245 UINT idxStride = 2;
5246 IWineD3DIndexBuffer *pIB;
5247 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5248 GLuint vbo;
5250 pIB = This->stateBlock->pIndexData;
5251 if (!pIB) {
5252 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5253 * without an index buffer set. (The first time at least...)
5254 * D3D8 simply dies, but I doubt it can do much harm to return
5255 * D3DERR_INVALIDCALL there as well. */
5256 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5257 return WINED3DERR_INVALIDCALL;
5260 if(!This->stateBlock->vertexDecl) {
5261 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5262 return WINED3DERR_INVALIDCALL;
5265 if(This->stateBlock->streamIsUP) {
5266 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5267 This->stateBlock->streamIsUP = FALSE;
5269 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5271 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5272 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5273 minIndex, NumVertices, startIndex, primCount);
5275 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5276 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5277 idxStride = 2;
5278 } else {
5279 idxStride = 4;
5282 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5283 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5284 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5287 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5288 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5290 return WINED3D_OK;
5293 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5294 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5295 UINT VertexStreamZeroStride) {
5296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5297 IWineD3DVertexBuffer *vb;
5299 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5300 debug_d3dprimitivetype(PrimitiveType),
5301 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5303 if(!This->stateBlock->vertexDecl) {
5304 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5305 return WINED3DERR_INVALIDCALL;
5308 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5309 vb = This->stateBlock->streamSource[0];
5310 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5311 if(vb) IWineD3DVertexBuffer_Release(vb);
5312 This->stateBlock->streamOffset[0] = 0;
5313 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5314 This->stateBlock->streamIsUP = TRUE;
5315 This->stateBlock->loadBaseVertexIndex = 0;
5317 /* TODO: Only mark dirty if drawing from a different UP address */
5318 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5320 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5321 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5323 /* MSDN specifies stream zero settings must be set to NULL */
5324 This->stateBlock->streamStride[0] = 0;
5325 This->stateBlock->streamSource[0] = NULL;
5327 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5328 * the new stream sources or use UP drawing again
5330 return WINED3D_OK;
5333 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5334 UINT MinVertexIndex, UINT NumVertices,
5335 UINT PrimitiveCount, CONST void* pIndexData,
5336 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5337 UINT VertexStreamZeroStride) {
5338 int idxStride;
5339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5340 IWineD3DVertexBuffer *vb;
5341 IWineD3DIndexBuffer *ib;
5343 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5344 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5345 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5346 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5348 if(!This->stateBlock->vertexDecl) {
5349 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5350 return WINED3DERR_INVALIDCALL;
5353 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5354 idxStride = 2;
5355 } else {
5356 idxStride = 4;
5359 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5360 vb = This->stateBlock->streamSource[0];
5361 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5362 if(vb) IWineD3DVertexBuffer_Release(vb);
5363 This->stateBlock->streamIsUP = TRUE;
5364 This->stateBlock->streamOffset[0] = 0;
5365 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5367 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5368 This->stateBlock->baseVertexIndex = 0;
5369 This->stateBlock->loadBaseVertexIndex = 0;
5370 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5371 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5372 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5374 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5376 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5377 This->stateBlock->streamSource[0] = NULL;
5378 This->stateBlock->streamStride[0] = 0;
5379 ib = This->stateBlock->pIndexData;
5380 if(ib) {
5381 IWineD3DIndexBuffer_Release(ib);
5382 This->stateBlock->pIndexData = NULL;
5384 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5385 * SetStreamSource to specify a vertex buffer
5388 return WINED3D_OK;
5391 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5392 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5394 /* Mark the state dirty until we have nicer tracking
5395 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5396 * that value.
5398 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5399 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5400 This->stateBlock->baseVertexIndex = 0;
5401 This->up_strided = DrawPrimStrideData;
5402 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5403 This->up_strided = NULL;
5404 return WINED3D_OK;
5407 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5409 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5411 /* Mark the state dirty until we have nicer tracking
5412 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5413 * that value.
5415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5416 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5417 This->stateBlock->streamIsUP = TRUE;
5418 This->stateBlock->baseVertexIndex = 0;
5419 This->up_strided = DrawPrimStrideData;
5420 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5421 This->up_strided = NULL;
5422 return WINED3D_OK;
5425 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5426 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5427 * not callable by the app directly no parameter validation checks are needed here.
5429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5430 WINED3DLOCKED_BOX src;
5431 WINED3DLOCKED_BOX dst;
5432 HRESULT hr;
5433 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5435 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5436 * dirtification to improve loading performance.
5438 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5439 if(FAILED(hr)) return hr;
5440 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5441 if(FAILED(hr)) {
5442 IWineD3DVolume_UnlockBox(pSourceVolume);
5443 return hr;
5446 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5448 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5449 if(FAILED(hr)) {
5450 IWineD3DVolume_UnlockBox(pSourceVolume);
5451 } else {
5452 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5454 return hr;
5457 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5458 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5459 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5460 HRESULT hr = WINED3D_OK;
5461 WINED3DRESOURCETYPE sourceType;
5462 WINED3DRESOURCETYPE destinationType;
5463 int i ,levels;
5465 /* TODO: think about moving the code into IWineD3DBaseTexture */
5467 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5469 /* verify that the source and destination textures aren't NULL */
5470 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5471 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5472 This, pSourceTexture, pDestinationTexture);
5473 hr = WINED3DERR_INVALIDCALL;
5476 if (pSourceTexture == pDestinationTexture) {
5477 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5478 This, pSourceTexture, pDestinationTexture);
5479 hr = WINED3DERR_INVALIDCALL;
5481 /* Verify that the source and destination textures are the same type */
5482 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5483 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5485 if (sourceType != destinationType) {
5486 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5487 This);
5488 hr = WINED3DERR_INVALIDCALL;
5491 /* check that both textures have the identical numbers of levels */
5492 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5493 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5494 hr = WINED3DERR_INVALIDCALL;
5497 if (WINED3D_OK == hr) {
5499 /* Make sure that the destination texture is loaded */
5500 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5502 /* Update every surface level of the texture */
5503 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5505 switch (sourceType) {
5506 case WINED3DRTYPE_TEXTURE:
5508 IWineD3DSurface *srcSurface;
5509 IWineD3DSurface *destSurface;
5511 for (i = 0 ; i < levels ; ++i) {
5512 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5513 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5514 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5515 IWineD3DSurface_Release(srcSurface);
5516 IWineD3DSurface_Release(destSurface);
5517 if (WINED3D_OK != hr) {
5518 WARN("(%p) : Call to update surface failed\n", This);
5519 return hr;
5523 break;
5524 case WINED3DRTYPE_CUBETEXTURE:
5526 IWineD3DSurface *srcSurface;
5527 IWineD3DSurface *destSurface;
5528 WINED3DCUBEMAP_FACES faceType;
5530 for (i = 0 ; i < levels ; ++i) {
5531 /* Update each cube face */
5532 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5533 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5534 if (WINED3D_OK != hr) {
5535 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5536 } else {
5537 TRACE("Got srcSurface %p\n", srcSurface);
5539 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5540 if (WINED3D_OK != hr) {
5541 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5542 } else {
5543 TRACE("Got desrSurface %p\n", destSurface);
5545 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5546 IWineD3DSurface_Release(srcSurface);
5547 IWineD3DSurface_Release(destSurface);
5548 if (WINED3D_OK != hr) {
5549 WARN("(%p) : Call to update surface failed\n", This);
5550 return hr;
5555 break;
5557 case WINED3DRTYPE_VOLUMETEXTURE:
5559 IWineD3DVolume *srcVolume = NULL;
5560 IWineD3DVolume *destVolume = NULL;
5562 for (i = 0 ; i < levels ; ++i) {
5563 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5564 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5565 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5566 IWineD3DVolume_Release(srcVolume);
5567 IWineD3DVolume_Release(destVolume);
5568 if (WINED3D_OK != hr) {
5569 WARN("(%p) : Call to update volume failed\n", This);
5570 return hr;
5574 break;
5576 default:
5577 FIXME("(%p) : Unsupported source and destination type\n", This);
5578 hr = WINED3DERR_INVALIDCALL;
5582 return hr;
5585 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5586 IWineD3DSwapChain *swapChain;
5587 HRESULT hr;
5588 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5589 if(hr == WINED3D_OK) {
5590 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5591 IWineD3DSwapChain_Release(swapChain);
5593 return hr;
5596 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5597 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5598 /* return a sensible default */
5599 *pNumPasses = 1;
5600 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5601 FIXME("(%p) : stub\n", This);
5602 return WINED3D_OK;
5605 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5607 int i;
5609 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5610 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5611 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5612 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5617 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5619 int j;
5620 UINT NewSize;
5621 PALETTEENTRY **palettes;
5623 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5625 if (PaletteNumber >= MAX_PALETTES) {
5626 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5627 return WINED3DERR_INVALIDCALL;
5630 if (PaletteNumber >= This->NumberOfPalettes) {
5631 NewSize = This->NumberOfPalettes;
5632 do {
5633 NewSize *= 2;
5634 } while(PaletteNumber >= NewSize);
5635 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5636 if (!palettes) {
5637 ERR("Out of memory!\n");
5638 return E_OUTOFMEMORY;
5640 This->palettes = palettes;
5641 This->NumberOfPalettes = NewSize;
5644 if (!This->palettes[PaletteNumber]) {
5645 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5646 if (!This->palettes[PaletteNumber]) {
5647 ERR("Out of memory!\n");
5648 return E_OUTOFMEMORY;
5652 for (j = 0; j < 256; ++j) {
5653 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5654 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5655 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5656 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5658 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5659 TRACE("(%p) : returning\n", This);
5660 return WINED3D_OK;
5663 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5664 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5665 int j;
5666 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5667 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5668 /* What happens in such situation isn't documented; Native seems to silently abort
5669 on such conditions. Return Invalid Call. */
5670 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5671 return WINED3DERR_INVALIDCALL;
5673 for (j = 0; j < 256; ++j) {
5674 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5675 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5676 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5677 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5679 TRACE("(%p) : returning\n", This);
5680 return WINED3D_OK;
5683 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5685 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5686 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5687 (tested with reference rasterizer). Return Invalid Call. */
5688 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5689 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5690 return WINED3DERR_INVALIDCALL;
5692 /*TODO: stateblocks */
5693 if (This->currentPalette != PaletteNumber) {
5694 This->currentPalette = PaletteNumber;
5695 dirtify_p8_texture_samplers(This);
5697 TRACE("(%p) : returning\n", This);
5698 return WINED3D_OK;
5701 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 if (PaletteNumber == NULL) {
5704 WARN("(%p) : returning Invalid Call\n", This);
5705 return WINED3DERR_INVALIDCALL;
5707 /*TODO: stateblocks */
5708 *PaletteNumber = This->currentPalette;
5709 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5710 return WINED3D_OK;
5713 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5715 static BOOL showFixmes = TRUE;
5716 if (showFixmes) {
5717 FIXME("(%p) : stub\n", This);
5718 showFixmes = FALSE;
5721 This->softwareVertexProcessing = bSoftware;
5722 return WINED3D_OK;
5726 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 static BOOL showFixmes = TRUE;
5729 if (showFixmes) {
5730 FIXME("(%p) : stub\n", This);
5731 showFixmes = FALSE;
5733 return This->softwareVertexProcessing;
5737 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5739 IWineD3DSwapChain *swapChain;
5740 HRESULT hr;
5742 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5744 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5745 if(hr == WINED3D_OK){
5746 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5747 IWineD3DSwapChain_Release(swapChain);
5748 }else{
5749 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5751 return hr;
5755 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5757 static BOOL showfixmes = TRUE;
5758 if(nSegments != 0.0f) {
5759 if( showfixmes) {
5760 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5761 showfixmes = FALSE;
5764 return WINED3D_OK;
5767 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5768 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5769 static BOOL showfixmes = TRUE;
5770 if( showfixmes) {
5771 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5772 showfixmes = FALSE;
5774 return 0.0f;
5777 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5778 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5779 /** TODO: remove casts to IWineD3DSurfaceImpl
5780 * NOTE: move code to surface to accomplish this
5781 ****************************************/
5782 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5783 int srcWidth, srcHeight;
5784 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5785 WINED3DFORMAT destFormat, srcFormat;
5786 UINT destSize;
5787 int srcLeft, destLeft, destTop;
5788 WINED3DPOOL srcPool, destPool;
5789 int offset = 0;
5790 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5791 glDescriptor *glDescription = NULL;
5792 GLenum dummy;
5793 int sampler;
5794 int bpp;
5795 CONVERT_TYPES convert = NO_CONVERSION;
5797 WINED3DSURFACE_DESC winedesc;
5799 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5800 memset(&winedesc, 0, sizeof(winedesc));
5801 winedesc.Width = &srcSurfaceWidth;
5802 winedesc.Height = &srcSurfaceHeight;
5803 winedesc.Pool = &srcPool;
5804 winedesc.Format = &srcFormat;
5806 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5808 winedesc.Width = &destSurfaceWidth;
5809 winedesc.Height = &destSurfaceHeight;
5810 winedesc.Pool = &destPool;
5811 winedesc.Format = &destFormat;
5812 winedesc.Size = &destSize;
5814 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5816 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5817 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5818 return WINED3DERR_INVALIDCALL;
5821 /* This call loads the opengl surface directly, instead of copying the surface to the
5822 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5823 * copy in sysmem and use regular surface loading.
5825 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5826 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5827 if(convert != NO_CONVERSION) {
5828 return IWineD3DSurface_BltFast(pDestinationSurface,
5829 pDestPoint ? pDestPoint->x : 0,
5830 pDestPoint ? pDestPoint->y : 0,
5831 pSourceSurface, (RECT *) pSourceRect, 0);
5834 if (destFormat == WINED3DFMT_UNKNOWN) {
5835 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5836 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5838 /* Get the update surface description */
5839 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5842 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5844 ENTER_GL();
5846 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5847 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5848 checkGLcall("glActiveTextureARB");
5851 /* Make sure the surface is loaded and up to date */
5852 IWineD3DSurface_PreLoad(pDestinationSurface);
5854 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5856 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5857 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5858 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5859 srcLeft = pSourceRect ? pSourceRect->left : 0;
5860 destLeft = pDestPoint ? pDestPoint->x : 0;
5861 destTop = pDestPoint ? pDestPoint->y : 0;
5864 /* This function doesn't support compressed textures
5865 the pitch is just bytesPerPixel * width */
5866 if(srcWidth != srcSurfaceWidth || srcLeft ){
5867 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5868 offset += srcLeft * pSrcSurface->bytesPerPixel;
5869 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5871 /* TODO DXT formats */
5873 if(pSourceRect != NULL && pSourceRect->top != 0){
5874 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5876 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5877 ,This
5878 ,glDescription->level
5879 ,destLeft
5880 ,destTop
5881 ,srcWidth
5882 ,srcHeight
5883 ,glDescription->glFormat
5884 ,glDescription->glType
5885 ,IWineD3DSurface_GetData(pSourceSurface)
5888 /* Sanity check */
5889 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5891 /* need to lock the surface to get the data */
5892 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5895 /* TODO: Cube and volume support */
5896 if(rowoffset != 0){
5897 /* not a whole row so we have to do it a line at a time */
5898 int j;
5900 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5901 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5903 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5905 glTexSubImage2D(glDescription->target
5906 ,glDescription->level
5907 ,destLeft
5909 ,srcWidth
5911 ,glDescription->glFormat
5912 ,glDescription->glType
5913 ,data /* could be quicker using */
5915 data += rowoffset;
5918 } else { /* Full width, so just write out the whole texture */
5920 if (WINED3DFMT_DXT1 == destFormat ||
5921 WINED3DFMT_DXT2 == destFormat ||
5922 WINED3DFMT_DXT3 == destFormat ||
5923 WINED3DFMT_DXT4 == destFormat ||
5924 WINED3DFMT_DXT5 == destFormat) {
5925 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5926 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5927 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5928 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5929 } if (destFormat != srcFormat) {
5930 FIXME("Updating mixed format compressed texture is not curretly support\n");
5931 } else {
5932 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5933 glDescription->level,
5934 glDescription->glFormatInternal,
5935 srcWidth,
5936 srcHeight,
5938 destSize,
5939 IWineD3DSurface_GetData(pSourceSurface));
5941 } else {
5942 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5946 } else {
5947 glTexSubImage2D(glDescription->target
5948 ,glDescription->level
5949 ,destLeft
5950 ,destTop
5951 ,srcWidth
5952 ,srcHeight
5953 ,glDescription->glFormat
5954 ,glDescription->glType
5955 ,IWineD3DSurface_GetData(pSourceSurface)
5959 checkGLcall("glTexSubImage2D");
5961 LEAVE_GL();
5963 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5964 sampler = This->rev_tex_unit_map[0];
5965 if (sampler != -1) {
5966 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5969 return WINED3D_OK;
5972 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5973 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5974 struct WineD3DRectPatch *patch;
5975 unsigned int i;
5976 struct list *e;
5977 BOOL found;
5978 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5980 if(!(Handle || pRectPatchInfo)) {
5981 /* TODO: Write a test for the return value, thus the FIXME */
5982 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5983 return WINED3DERR_INVALIDCALL;
5986 if(Handle) {
5987 i = PATCHMAP_HASHFUNC(Handle);
5988 found = FALSE;
5989 LIST_FOR_EACH(e, &This->patches[i]) {
5990 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5991 if(patch->Handle == Handle) {
5992 found = TRUE;
5993 break;
5997 if(!found) {
5998 TRACE("Patch does not exist. Creating a new one\n");
5999 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6000 patch->Handle = Handle;
6001 list_add_head(&This->patches[i], &patch->entry);
6002 } else {
6003 TRACE("Found existing patch %p\n", patch);
6005 } else {
6006 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6007 * attributes we have to tesselate, read back, and draw. This needs a patch
6008 * management structure instance. Create one.
6010 * A possible improvement is to check if a vertex shader is used, and if not directly
6011 * draw the patch.
6013 FIXME("Drawing an uncached patch. This is slow\n");
6014 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6017 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6018 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6019 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6020 HRESULT hr;
6021 TRACE("Tesselation density or patch info changed, retesselating\n");
6023 if(pRectPatchInfo) {
6024 patch->RectPatchInfo = *pRectPatchInfo;
6026 patch->numSegs[0] = pNumSegs[0];
6027 patch->numSegs[1] = pNumSegs[1];
6028 patch->numSegs[2] = pNumSegs[2];
6029 patch->numSegs[3] = pNumSegs[3];
6031 hr = tesselate_rectpatch(This, patch);
6032 if(FAILED(hr)) {
6033 WARN("Patch tesselation failed\n");
6035 /* Do not release the handle to store the params of the patch */
6036 if(!Handle) {
6037 HeapFree(GetProcessHeap(), 0, patch);
6039 return hr;
6043 This->currentPatch = patch;
6044 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6045 This->currentPatch = NULL;
6047 /* Destroy uncached patches */
6048 if(!Handle) {
6049 HeapFree(GetProcessHeap(), 0, patch->mem);
6050 HeapFree(GetProcessHeap(), 0, patch);
6052 return WINED3D_OK;
6055 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6057 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6058 FIXME("(%p) : Stub\n", This);
6059 return WINED3D_OK;
6062 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6063 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6064 int i;
6065 struct WineD3DRectPatch *patch;
6066 struct list *e;
6067 TRACE("(%p) Handle(%d)\n", This, Handle);
6069 i = PATCHMAP_HASHFUNC(Handle);
6070 LIST_FOR_EACH(e, &This->patches[i]) {
6071 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6072 if(patch->Handle == Handle) {
6073 TRACE("Deleting patch %p\n", patch);
6074 list_remove(&patch->entry);
6075 HeapFree(GetProcessHeap(), 0, patch->mem);
6076 HeapFree(GetProcessHeap(), 0, patch);
6077 return WINED3D_OK;
6081 /* TODO: Write a test for the return value */
6082 FIXME("Attempt to destroy nonexistent patch\n");
6083 return WINED3DERR_INVALIDCALL;
6086 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6087 HRESULT hr;
6088 IWineD3DSwapChain *swapchain;
6090 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6091 if (SUCCEEDED(hr)) {
6092 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6093 return swapchain;
6096 return NULL;
6099 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6100 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6102 if (!*fbo) {
6103 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6104 checkGLcall("glGenFramebuffersEXT()");
6106 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6107 checkGLcall("glBindFramebuffer()");
6110 /* TODO: Handle stencil attachments */
6111 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6112 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6114 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6115 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6116 checkGLcall("glFramebufferRenderbufferEXT()");
6117 } else {
6118 IWineD3DBaseTextureImpl *texture_impl;
6119 GLenum texttarget, target;
6120 GLint old_binding = 0;
6122 texttarget = depth_stencil_impl->glDescription.target;
6123 if(texttarget == GL_TEXTURE_2D) {
6124 target = GL_TEXTURE_2D;
6125 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6126 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6127 target = GL_TEXTURE_RECTANGLE_ARB;
6128 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6129 } else {
6130 target = GL_TEXTURE_CUBE_MAP_ARB;
6131 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6134 IWineD3DSurface_PreLoad(depth_stencil);
6136 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6137 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6138 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6139 glBindTexture(target, old_binding);
6141 /* Update base texture states array */
6142 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6143 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6144 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6145 if (texture_impl->baseTexture.bindCount) {
6146 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6149 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6152 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6153 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6154 checkGLcall("glFramebufferTexture2DEXT()");
6158 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6159 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6160 IWineD3DBaseTextureImpl *texture_impl;
6161 GLenum texttarget, target;
6162 GLint old_binding;
6164 texttarget = surface_impl->glDescription.target;
6165 if(texttarget == GL_TEXTURE_2D) {
6166 target = GL_TEXTURE_2D;
6167 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6168 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6169 target = GL_TEXTURE_RECTANGLE_ARB;
6170 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6171 } else {
6172 target = GL_TEXTURE_CUBE_MAP_ARB;
6173 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6176 IWineD3DSurface_PreLoad(surface);
6178 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6179 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6180 glBindTexture(target, old_binding);
6182 /* Update base texture states array */
6183 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6184 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6185 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6186 if (texture_impl->baseTexture.bindCount) {
6187 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6190 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6193 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6194 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6196 checkGLcall("attach_surface_fbo");
6199 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6200 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6201 IWineD3DSwapChain *swapchain;
6203 swapchain = get_swapchain(surface);
6204 if (swapchain) {
6205 GLenum buffer;
6207 TRACE("Surface %p is onscreen\n", surface);
6209 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6210 ENTER_GL();
6211 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6212 buffer = surface_get_gl_buffer(surface, swapchain);
6213 glDrawBuffer(buffer);
6214 checkGLcall("glDrawBuffer()");
6215 } else {
6216 TRACE("Surface %p is offscreen\n", surface);
6218 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6219 ENTER_GL();
6220 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6221 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6222 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6223 checkGLcall("glFramebufferRenderbufferEXT");
6226 if (rect) {
6227 glEnable(GL_SCISSOR_TEST);
6228 if(!swapchain) {
6229 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6230 } else {
6231 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6232 rect->x2 - rect->x1, rect->y2 - rect->y1);
6234 checkGLcall("glScissor");
6235 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6236 } else {
6237 glDisable(GL_SCISSOR_TEST);
6239 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6241 glDisable(GL_BLEND);
6242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6244 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6245 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6247 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6248 glClear(GL_COLOR_BUFFER_BIT);
6249 checkGLcall("glClear");
6251 if (This->render_offscreen) {
6252 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6253 } else {
6254 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6255 checkGLcall("glBindFramebuffer()");
6258 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6259 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6260 glDrawBuffer(GL_BACK);
6261 checkGLcall("glDrawBuffer()");
6264 LEAVE_GL();
6267 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6268 unsigned int r, g, b, a;
6269 DWORD ret;
6271 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6272 destfmt == WINED3DFMT_R8G8B8)
6273 return color;
6275 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6277 a = (color & 0xff000000) >> 24;
6278 r = (color & 0x00ff0000) >> 16;
6279 g = (color & 0x0000ff00) >> 8;
6280 b = (color & 0x000000ff) >> 0;
6282 switch(destfmt)
6284 case WINED3DFMT_R5G6B5:
6285 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6286 r = (r * 32) / 256;
6287 g = (g * 64) / 256;
6288 b = (b * 32) / 256;
6289 ret = r << 11;
6290 ret |= g << 5;
6291 ret |= b;
6292 TRACE("Returning %08x\n", ret);
6293 return ret;
6295 case WINED3DFMT_X1R5G5B5:
6296 case WINED3DFMT_A1R5G5B5:
6297 a = (a * 2) / 256;
6298 r = (r * 32) / 256;
6299 g = (g * 32) / 256;
6300 b = (b * 32) / 256;
6301 ret = a << 15;
6302 ret |= r << 10;
6303 ret |= g << 5;
6304 ret |= b << 0;
6305 TRACE("Returning %08x\n", ret);
6306 return ret;
6308 case WINED3DFMT_A8:
6309 TRACE("Returning %08x\n", a);
6310 return a;
6312 case WINED3DFMT_X4R4G4B4:
6313 case WINED3DFMT_A4R4G4B4:
6314 a = (a * 16) / 256;
6315 r = (r * 16) / 256;
6316 g = (g * 16) / 256;
6317 b = (b * 16) / 256;
6318 ret = a << 12;
6319 ret |= r << 8;
6320 ret |= g << 4;
6321 ret |= b << 0;
6322 TRACE("Returning %08x\n", ret);
6323 return ret;
6325 case WINED3DFMT_R3G3B2:
6326 r = (r * 8) / 256;
6327 g = (g * 8) / 256;
6328 b = (b * 4) / 256;
6329 ret = r << 5;
6330 ret |= g << 2;
6331 ret |= b << 0;
6332 TRACE("Returning %08x\n", ret);
6333 return ret;
6335 case WINED3DFMT_X8B8G8R8:
6336 case WINED3DFMT_A8B8G8R8:
6337 ret = a << 24;
6338 ret |= b << 16;
6339 ret |= g << 8;
6340 ret |= r << 0;
6341 TRACE("Returning %08x\n", ret);
6342 return ret;
6344 case WINED3DFMT_A2R10G10B10:
6345 a = (a * 4) / 256;
6346 r = (r * 1024) / 256;
6347 g = (g * 1024) / 256;
6348 b = (b * 1024) / 256;
6349 ret = a << 30;
6350 ret |= r << 20;
6351 ret |= g << 10;
6352 ret |= b << 0;
6353 TRACE("Returning %08x\n", ret);
6354 return ret;
6356 case WINED3DFMT_A2B10G10R10:
6357 a = (a * 4) / 256;
6358 r = (r * 1024) / 256;
6359 g = (g * 1024) / 256;
6360 b = (b * 1024) / 256;
6361 ret = a << 30;
6362 ret |= b << 20;
6363 ret |= g << 10;
6364 ret |= r << 0;
6365 TRACE("Returning %08x\n", ret);
6366 return ret;
6368 default:
6369 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6370 return 0;
6374 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6375 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6376 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6377 WINEDDBLTFX BltFx;
6378 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6380 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6381 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6382 return WINED3DERR_INVALIDCALL;
6385 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6386 color_fill_fbo(iface, pSurface, pRect, color);
6387 return WINED3D_OK;
6388 } else {
6389 /* Just forward this to the DirectDraw blitting engine */
6390 memset(&BltFx, 0, sizeof(BltFx));
6391 BltFx.dwSize = sizeof(BltFx);
6392 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6393 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6397 /* rendertarget and depth stencil functions */
6398 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6399 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6401 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6402 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6403 return WINED3DERR_INVALIDCALL;
6406 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6407 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6408 /* Note inc ref on returned surface */
6409 if(*ppRenderTarget != NULL)
6410 IWineD3DSurface_AddRef(*ppRenderTarget);
6411 return WINED3D_OK;
6414 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6415 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6416 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6417 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6418 IWineD3DSwapChainImpl *Swapchain;
6419 HRESULT hr;
6421 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6423 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6424 if(hr != WINED3D_OK) {
6425 ERR("Can't get the swapchain\n");
6426 return hr;
6429 /* Make sure to release the swapchain */
6430 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6432 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6433 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6434 return WINED3DERR_INVALIDCALL;
6436 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6437 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6438 return WINED3DERR_INVALIDCALL;
6441 if(Swapchain->frontBuffer != Front) {
6442 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6444 if(Swapchain->frontBuffer)
6445 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6446 Swapchain->frontBuffer = Front;
6448 if(Swapchain->frontBuffer) {
6449 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6453 if(Back && !Swapchain->backBuffer) {
6454 /* We need memory for the back buffer array - only one back buffer this way */
6455 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6456 if(!Swapchain->backBuffer) {
6457 ERR("Out of memory\n");
6458 return E_OUTOFMEMORY;
6462 if(Swapchain->backBuffer[0] != Back) {
6463 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6465 /* What to do about the context here in the case of multithreading? Not sure.
6466 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6468 ENTER_GL();
6469 if(!Swapchain->backBuffer[0]) {
6470 /* GL was told to draw to the front buffer at creation,
6471 * undo that
6473 glDrawBuffer(GL_BACK);
6474 checkGLcall("glDrawBuffer(GL_BACK)");
6475 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6476 Swapchain->presentParms.BackBufferCount = 1;
6477 } else if (!Back) {
6478 /* That makes problems - disable for now */
6479 /* glDrawBuffer(GL_FRONT); */
6480 checkGLcall("glDrawBuffer(GL_FRONT)");
6481 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6482 Swapchain->presentParms.BackBufferCount = 0;
6484 LEAVE_GL();
6486 if(Swapchain->backBuffer[0])
6487 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6488 Swapchain->backBuffer[0] = Back;
6490 if(Swapchain->backBuffer[0]) {
6491 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6492 } else {
6493 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6494 Swapchain->backBuffer = NULL;
6499 return WINED3D_OK;
6502 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6503 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6504 *ppZStencilSurface = This->stencilBufferTarget;
6505 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6507 if(*ppZStencilSurface != NULL) {
6508 /* Note inc ref on returned surface */
6509 IWineD3DSurface_AddRef(*ppZStencilSurface);
6510 return WINED3D_OK;
6511 } else {
6512 return WINED3DERR_NOTFOUND;
6516 /* TODO: Handle stencil attachments */
6517 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6520 TRACE("Set depth stencil to %p\n", depth_stencil);
6522 if (depth_stencil) {
6523 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6524 } else {
6525 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6526 checkGLcall("glFramebufferTexture2DEXT()");
6530 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 TRACE("Set render target %u to %p\n", idx, render_target);
6535 if (render_target) {
6536 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6537 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6538 } else {
6539 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6540 checkGLcall("glFramebufferTexture2DEXT()");
6542 This->draw_buffers[idx] = GL_NONE;
6546 static void check_fbo_status(IWineD3DDevice *iface) {
6547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6548 GLenum status;
6550 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6551 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6552 TRACE("FBO complete\n");
6553 } else {
6554 IWineD3DSurfaceImpl *attachment;
6555 int i;
6556 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6558 /* Dump the FBO attachments */
6559 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6560 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6561 if (attachment) {
6562 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6563 attachment->pow2Width, attachment->pow2Height);
6566 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6567 if (attachment) {
6568 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6569 attachment->pow2Width, attachment->pow2Height);
6574 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6575 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6576 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6577 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6579 if (!ds_impl) return FALSE;
6581 if (ds_impl->current_renderbuffer) {
6582 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6583 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6586 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6587 rt_impl->pow2Height != ds_impl->pow2Height);
6590 void apply_fbo_state(IWineD3DDevice *iface) {
6591 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6592 unsigned int i;
6594 if (This->render_offscreen) {
6595 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6597 /* Apply render targets */
6598 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6599 IWineD3DSurface *render_target = This->render_targets[i];
6600 if (This->fbo_color_attachments[i] != render_target) {
6601 set_render_target_fbo(iface, i, render_target);
6602 This->fbo_color_attachments[i] = render_target;
6606 /* Apply depth targets */
6607 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6608 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6609 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6611 if (This->stencilBufferTarget) {
6612 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6614 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6615 This->fbo_depth_attachment = This->stencilBufferTarget;
6617 } else {
6618 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6621 check_fbo_status(iface);
6624 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6625 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6626 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6627 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6628 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6629 GLenum gl_filter;
6630 POINT offset = {0, 0};
6632 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6633 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6634 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6635 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6637 switch (filter) {
6638 case WINED3DTEXF_LINEAR:
6639 gl_filter = GL_LINEAR;
6640 break;
6642 default:
6643 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6644 case WINED3DTEXF_NONE:
6645 case WINED3DTEXF_POINT:
6646 gl_filter = GL_NEAREST;
6647 break;
6650 /* Attach src surface to src fbo */
6651 src_swapchain = get_swapchain(src_surface);
6652 if (src_swapchain) {
6653 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6655 TRACE("Source surface %p is onscreen\n", src_surface);
6656 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6657 /* Make sure the drawable is up to date. In the offscreen case
6658 * attach_surface_fbo() implicitly takes care of this. */
6659 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6661 if(buffer == GL_FRONT) {
6662 RECT windowsize;
6663 UINT h;
6664 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6665 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6666 h = windowsize.bottom - windowsize.top;
6667 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6668 src_rect->y1 = offset.y + h - src_rect->y1;
6669 src_rect->y2 = offset.y + h - src_rect->y2;
6670 } else {
6671 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6672 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6675 ENTER_GL();
6676 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6677 glReadBuffer(buffer);
6678 checkGLcall("glReadBuffer()");
6679 } else {
6680 TRACE("Source surface %p is offscreen\n", src_surface);
6681 ENTER_GL();
6682 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6683 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6684 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6685 checkGLcall("glReadBuffer()");
6686 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6687 checkGLcall("glFramebufferRenderbufferEXT");
6689 LEAVE_GL();
6691 /* Attach dst surface to dst fbo */
6692 dst_swapchain = get_swapchain(dst_surface);
6693 if (dst_swapchain) {
6694 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6696 TRACE("Destination surface %p is onscreen\n", dst_surface);
6697 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6698 /* Make sure the drawable is up to date. In the offscreen case
6699 * attach_surface_fbo() implicitly takes care of this. */
6700 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6702 if(buffer == GL_FRONT) {
6703 RECT windowsize;
6704 UINT h;
6705 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6706 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6707 h = windowsize.bottom - windowsize.top;
6708 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6709 dst_rect->y1 = offset.y + h - dst_rect->y1;
6710 dst_rect->y2 = offset.y + h - dst_rect->y2;
6711 } else {
6712 /* Screen coords = window coords, surface height = window height */
6713 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6714 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6717 ENTER_GL();
6718 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6719 glDrawBuffer(buffer);
6720 checkGLcall("glDrawBuffer()");
6721 } else {
6722 TRACE("Destination surface %p is offscreen\n", dst_surface);
6724 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6725 if(!src_swapchain) {
6726 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6729 ENTER_GL();
6730 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6731 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6732 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6733 checkGLcall("glDrawBuffer()");
6734 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6735 checkGLcall("glFramebufferRenderbufferEXT");
6737 glDisable(GL_SCISSOR_TEST);
6738 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6740 if (flip) {
6741 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6742 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6743 checkGLcall("glBlitFramebuffer()");
6744 } else {
6745 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6746 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6747 checkGLcall("glBlitFramebuffer()");
6750 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6752 if (This->render_offscreen) {
6753 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6754 } else {
6755 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6756 checkGLcall("glBindFramebuffer()");
6759 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6760 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6761 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6762 glDrawBuffer(GL_BACK);
6763 checkGLcall("glDrawBuffer()");
6765 LEAVE_GL();
6768 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6770 WINED3DVIEWPORT viewport;
6772 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6774 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6775 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6776 This, RenderTargetIndex, GL_LIMITS(buffers));
6777 return WINED3DERR_INVALIDCALL;
6780 /* MSDN says that null disables the render target
6781 but a device must always be associated with a render target
6782 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6784 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6785 FIXME("Trying to set render target 0 to NULL\n");
6786 return WINED3DERR_INVALIDCALL;
6788 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6789 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);
6790 return WINED3DERR_INVALIDCALL;
6793 /* If we are trying to set what we already have, don't bother */
6794 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6795 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6796 return WINED3D_OK;
6798 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6799 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6800 This->render_targets[RenderTargetIndex] = pRenderTarget;
6802 /* Render target 0 is special */
6803 if(RenderTargetIndex == 0) {
6804 /* Finally, reset the viewport as the MSDN states. */
6805 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6806 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6807 viewport.X = 0;
6808 viewport.Y = 0;
6809 viewport.MaxZ = 1.0f;
6810 viewport.MinZ = 0.0f;
6811 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6812 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6813 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6815 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6817 return WINED3D_OK;
6820 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6821 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6822 HRESULT hr = WINED3D_OK;
6823 IWineD3DSurface *tmp;
6825 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6827 if (pNewZStencil == This->stencilBufferTarget) {
6828 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6829 } else {
6830 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6831 * depending on the renter target implementation being used.
6832 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6833 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6834 * stencil buffer and incur an extra memory overhead
6835 ******************************************************/
6837 if (This->stencilBufferTarget) {
6838 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6839 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6840 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6843 tmp = This->stencilBufferTarget;
6844 This->stencilBufferTarget = pNewZStencil;
6845 /* should we be calling the parent or the wined3d surface? */
6846 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6847 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6848 hr = WINED3D_OK;
6850 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6851 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6852 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6853 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6854 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6858 return hr;
6861 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6862 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6864 /* TODO: the use of Impl is deprecated. */
6865 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6866 WINED3DLOCKED_RECT lockedRect;
6868 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6870 /* some basic validation checks */
6871 if(This->cursorTexture) {
6872 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6873 ENTER_GL();
6874 glDeleteTextures(1, &This->cursorTexture);
6875 LEAVE_GL();
6876 This->cursorTexture = 0;
6879 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6880 This->haveHardwareCursor = TRUE;
6881 else
6882 This->haveHardwareCursor = FALSE;
6884 if(pCursorBitmap) {
6885 WINED3DLOCKED_RECT rect;
6887 /* MSDN: Cursor must be A8R8G8B8 */
6888 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6889 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6890 return WINED3DERR_INVALIDCALL;
6893 /* MSDN: Cursor must be smaller than the display mode */
6894 if(pSur->currentDesc.Width > This->ddraw_width ||
6895 pSur->currentDesc.Height > This->ddraw_height) {
6896 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);
6897 return WINED3DERR_INVALIDCALL;
6900 if (!This->haveHardwareCursor) {
6901 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6903 /* Do not store the surface's pointer because the application may
6904 * release it after setting the cursor image. Windows doesn't
6905 * addref the set surface, so we can't do this either without
6906 * creating circular refcount dependencies. Copy out the gl texture
6907 * instead.
6909 This->cursorWidth = pSur->currentDesc.Width;
6910 This->cursorHeight = pSur->currentDesc.Height;
6911 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6913 const GlPixelFormatDesc *glDesc;
6914 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6915 char *mem, *bits = (char *)rect.pBits;
6916 GLint intfmt = glDesc->glInternal;
6917 GLint format = glDesc->glFormat;
6918 GLint type = glDesc->glType;
6919 INT height = This->cursorHeight;
6920 INT width = This->cursorWidth;
6921 INT bpp = tableEntry->bpp;
6922 INT i, sampler;
6924 /* Reformat the texture memory (pitch and width can be
6925 * different) */
6926 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6927 for(i = 0; i < height; i++)
6928 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6929 IWineD3DSurface_UnlockRect(pCursorBitmap);
6930 ENTER_GL();
6932 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6933 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6934 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6937 /* Make sure that a proper texture unit is selected */
6938 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6939 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6940 checkGLcall("glActiveTextureARB");
6942 sampler = This->rev_tex_unit_map[0];
6943 if (sampler != -1) {
6944 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6946 /* Create a new cursor texture */
6947 glGenTextures(1, &This->cursorTexture);
6948 checkGLcall("glGenTextures");
6949 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6950 checkGLcall("glBindTexture");
6951 /* Copy the bitmap memory into the cursor texture */
6952 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6953 HeapFree(GetProcessHeap(), 0, mem);
6954 checkGLcall("glTexImage2D");
6956 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6957 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6958 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6961 LEAVE_GL();
6963 else
6965 FIXME("A cursor texture was not returned.\n");
6966 This->cursorTexture = 0;
6969 else
6971 /* Draw a hardware cursor */
6972 ICONINFO cursorInfo;
6973 HCURSOR cursor;
6974 /* Create and clear maskBits because it is not needed for
6975 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6976 * chunks. */
6977 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6978 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6979 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6980 WINED3DLOCK_NO_DIRTY_UPDATE |
6981 WINED3DLOCK_READONLY
6983 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6984 pSur->currentDesc.Height);
6986 cursorInfo.fIcon = FALSE;
6987 cursorInfo.xHotspot = XHotSpot;
6988 cursorInfo.yHotspot = YHotSpot;
6989 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6990 pSur->currentDesc.Height, 1,
6991 1, &maskBits);
6992 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6993 pSur->currentDesc.Height, 1,
6994 32, lockedRect.pBits);
6995 IWineD3DSurface_UnlockRect(pCursorBitmap);
6996 /* Create our cursor and clean up. */
6997 cursor = CreateIconIndirect(&cursorInfo);
6998 SetCursor(cursor);
6999 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7000 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7001 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7002 This->hardwareCursor = cursor;
7003 HeapFree(GetProcessHeap(), 0, maskBits);
7007 This->xHotSpot = XHotSpot;
7008 This->yHotSpot = YHotSpot;
7009 return WINED3D_OK;
7012 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7013 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7014 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7016 This->xScreenSpace = XScreenSpace;
7017 This->yScreenSpace = YScreenSpace;
7019 return;
7023 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7025 BOOL oldVisible = This->bCursorVisible;
7026 POINT pt;
7028 TRACE("(%p) : visible(%d)\n", This, bShow);
7031 * When ShowCursor is first called it should make the cursor appear at the OS's last
7032 * known cursor position. Because of this, some applications just repetitively call
7033 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7035 GetCursorPos(&pt);
7036 This->xScreenSpace = pt.x;
7037 This->yScreenSpace = pt.y;
7039 if (This->haveHardwareCursor) {
7040 This->bCursorVisible = bShow;
7041 if (bShow)
7042 SetCursor(This->hardwareCursor);
7043 else
7044 SetCursor(NULL);
7046 else
7048 if (This->cursorTexture)
7049 This->bCursorVisible = bShow;
7052 return oldVisible;
7055 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7056 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7057 IWineD3DResourceImpl *resource;
7058 TRACE("(%p) : state (%u)\n", This, This->state);
7060 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7061 switch (This->state) {
7062 case WINED3D_OK:
7063 return WINED3D_OK;
7064 case WINED3DERR_DEVICELOST:
7066 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7067 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7068 return WINED3DERR_DEVICENOTRESET;
7070 return WINED3DERR_DEVICELOST;
7072 case WINED3DERR_DRIVERINTERNALERROR:
7073 return WINED3DERR_DRIVERINTERNALERROR;
7076 /* Unknown state */
7077 return WINED3DERR_DRIVERINTERNALERROR;
7081 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7083 /** FIXME: Resource tracking needs to be done,
7084 * The closes we can do to this is set the priorities of all managed textures low
7085 * and then reset them.
7086 ***********************************************************/
7087 FIXME("(%p) : stub\n", This);
7088 return WINED3D_OK;
7091 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7092 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7094 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7095 if(surface->Flags & SFLAG_DIBSECTION) {
7096 /* Release the DC */
7097 SelectObject(surface->hDC, surface->dib.holdbitmap);
7098 DeleteDC(surface->hDC);
7099 /* Release the DIB section */
7100 DeleteObject(surface->dib.DIBsection);
7101 surface->dib.bitmap_data = NULL;
7102 surface->resource.allocatedMemory = NULL;
7103 surface->Flags &= ~SFLAG_DIBSECTION;
7105 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7106 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7107 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7108 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7109 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7110 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7111 } else {
7112 surface->pow2Width = surface->pow2Height = 1;
7113 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7114 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7116 surface->glRect.left = 0;
7117 surface->glRect.top = 0;
7118 surface->glRect.right = surface->pow2Width;
7119 surface->glRect.bottom = surface->pow2Height;
7121 if(surface->glDescription.textureName) {
7122 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7123 ENTER_GL();
7124 glDeleteTextures(1, &surface->glDescription.textureName);
7125 LEAVE_GL();
7126 surface->glDescription.textureName = 0;
7127 surface->Flags &= ~SFLAG_CLIENT;
7129 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7130 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7131 surface->Flags |= SFLAG_NONPOW2;
7132 } else {
7133 surface->Flags &= ~SFLAG_NONPOW2;
7135 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7136 surface->resource.allocatedMemory = NULL;
7137 surface->resource.heapMemory = NULL;
7138 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7139 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7140 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7141 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7142 } else {
7143 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7147 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7148 TRACE("Unloading resource %p\n", resource);
7149 IWineD3DResource_UnLoad(resource);
7150 IWineD3DResource_Release(resource);
7151 return S_OK;
7154 static void reset_fbo_state(IWineD3DDevice *iface) {
7155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7156 unsigned int i;
7158 ENTER_GL();
7159 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7160 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7162 if (This->fbo) {
7163 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7164 This->fbo = 0;
7166 if (This->src_fbo) {
7167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7168 This->src_fbo = 0;
7170 if (This->dst_fbo) {
7171 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7172 This->dst_fbo = 0;
7174 checkGLcall("Tear down FBOs\n");
7175 LEAVE_GL();
7177 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7178 This->fbo_color_attachments[i] = NULL;
7180 This->fbo_depth_attachment = NULL;
7183 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7184 UINT i, count;
7185 WINED3DDISPLAYMODE m;
7186 HRESULT hr;
7188 /* All Windowed modes are supported, as is leaving the current mode */
7189 if(pp->Windowed) return TRUE;
7190 if(!pp->BackBufferWidth) return TRUE;
7191 if(!pp->BackBufferHeight) return TRUE;
7193 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7194 for(i = 0; i < count; i++) {
7195 memset(&m, 0, sizeof(m));
7196 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7197 if(FAILED(hr)) {
7198 ERR("EnumAdapterModes failed\n");
7200 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7201 /* Mode found, it is supported */
7202 return TRUE;
7205 /* Mode not found -> not supported */
7206 return FALSE;
7209 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7211 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7212 UINT i;
7213 IWineD3DBaseShaderImpl *shader;
7215 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7216 reset_fbo_state((IWineD3DDevice *) This);
7219 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7220 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7221 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7224 ENTER_GL();
7225 if(This->depth_blt_texture) {
7226 glDeleteTextures(1, &This->depth_blt_texture);
7227 This->depth_blt_texture = 0;
7229 if (This->depth_blt_rb) {
7230 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7231 This->depth_blt_rb = 0;
7232 This->depth_blt_rb_w = 0;
7233 This->depth_blt_rb_h = 0;
7235 This->blitter->free_private(iface);
7236 This->frag_pipe->free_private(iface);
7237 This->shader_backend->shader_free_private(iface);
7239 for (i = 0; i < GL_LIMITS(textures); i++) {
7240 /* Textures are recreated below */
7241 glDeleteTextures(1, &This->dummyTextureName[i]);
7242 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7243 This->dummyTextureName[i] = 0;
7245 LEAVE_GL();
7247 while(This->numContexts) {
7248 DestroyContext(This, This->contexts[0]);
7250 This->activeContext = NULL;
7251 HeapFree(GetProcessHeap(), 0, swapchain->context);
7252 swapchain->context = NULL;
7253 swapchain->num_contexts = 0;
7256 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7258 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7259 HRESULT hr;
7260 IWineD3DSurfaceImpl *target;
7262 /* Recreate the primary swapchain's context */
7263 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7264 if(swapchain->backBuffer) {
7265 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7266 } else {
7267 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7269 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7270 &swapchain->presentParms);
7271 swapchain->num_contexts = 1;
7272 This->activeContext = swapchain->context[0];
7274 create_dummy_textures(This);
7276 hr = This->shader_backend->shader_alloc_private(iface);
7277 if(FAILED(hr)) {
7278 ERR("Failed to recreate shader private data\n");
7279 goto err_out;
7281 hr = This->frag_pipe->alloc_private(iface);
7282 if(FAILED(hr)) {
7283 TRACE("Fragment pipeline private data couldn't be allocated\n");
7284 goto err_out;
7286 hr = This->blitter->alloc_private(iface);
7287 if(FAILED(hr)) {
7288 TRACE("Blitter private data couldn't be allocated\n");
7289 goto err_out;
7292 return WINED3D_OK;
7294 err_out:
7295 This->blitter->free_private(iface);
7296 This->frag_pipe->free_private(iface);
7297 This->shader_backend->shader_free_private(iface);
7298 return hr;
7301 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7302 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7303 IWineD3DSwapChainImpl *swapchain;
7304 HRESULT hr;
7305 BOOL DisplayModeChanged = FALSE;
7306 WINED3DDISPLAYMODE mode;
7307 TRACE("(%p)\n", This);
7309 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7310 if(FAILED(hr)) {
7311 ERR("Failed to get the first implicit swapchain\n");
7312 return hr;
7315 if(!is_display_mode_supported(This, pPresentationParameters)) {
7316 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7317 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7318 pPresentationParameters->BackBufferHeight);
7319 return WINED3DERR_INVALIDCALL;
7322 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7323 * on an existing gl context, so there's no real need for recreation.
7325 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7327 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7329 TRACE("New params:\n");
7330 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7331 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7332 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7333 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7334 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7335 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7336 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7337 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7338 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7339 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7340 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7341 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7342 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7344 /* No special treatment of these parameters. Just store them */
7345 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7346 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7347 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7348 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7350 /* What to do about these? */
7351 if(pPresentationParameters->BackBufferCount != 0 &&
7352 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7353 ERR("Cannot change the back buffer count yet\n");
7355 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7356 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7357 ERR("Cannot change the back buffer format yet\n");
7359 if(pPresentationParameters->hDeviceWindow != NULL &&
7360 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7361 ERR("Cannot change the device window yet\n");
7363 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7364 ERR("What do do about a changed auto depth stencil parameter?\n");
7367 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7369 if(pPresentationParameters->Windowed) {
7370 mode.Width = swapchain->orig_width;
7371 mode.Height = swapchain->orig_height;
7372 mode.RefreshRate = 0;
7373 mode.Format = swapchain->presentParms.BackBufferFormat;
7374 } else {
7375 mode.Width = pPresentationParameters->BackBufferWidth;
7376 mode.Height = pPresentationParameters->BackBufferHeight;
7377 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7378 mode.Format = swapchain->presentParms.BackBufferFormat;
7380 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
7381 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
7382 pPresentationParameters->BackBufferWidth,
7383 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
7386 /* Should Width == 800 && Height == 0 set 800x600? */
7387 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7388 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7389 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7391 WINED3DVIEWPORT vp;
7392 int i;
7394 vp.X = 0;
7395 vp.Y = 0;
7396 vp.Width = pPresentationParameters->BackBufferWidth;
7397 vp.Height = pPresentationParameters->BackBufferHeight;
7398 vp.MinZ = 0;
7399 vp.MaxZ = 1;
7401 if(!pPresentationParameters->Windowed) {
7402 DisplayModeChanged = TRUE;
7404 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7405 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7407 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7408 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7409 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7411 if(This->auto_depth_stencil_buffer) {
7412 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7416 /* Now set the new viewport */
7417 IWineD3DDevice_SetViewport(iface, &vp);
7420 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7421 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7422 DisplayModeChanged) {
7424 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7426 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7427 if(swapchain->presentParms.Windowed) {
7428 /* switch from windowed to fs */
7429 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7430 pPresentationParameters->BackBufferWidth,
7431 pPresentationParameters->BackBufferHeight);
7432 } else {
7433 /* Fullscreen -> fullscreen mode change */
7434 MoveWindow(swapchain->win_handle, 0, 0,
7435 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7436 TRUE);
7438 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7439 /* Fullscreen -> windowed switch */
7440 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7442 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7443 } else if(!pPresentationParameters->Windowed) {
7444 DWORD style = This->style, exStyle = This->exStyle;
7445 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7446 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7447 * Reset to clear up their mess. Guild Wars also loses the device during that.
7449 This->style = 0;
7450 This->exStyle = 0;
7451 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7452 pPresentationParameters->BackBufferWidth,
7453 pPresentationParameters->BackBufferHeight);
7454 This->style = style;
7455 This->exStyle = exStyle;
7458 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7459 if(FAILED(hr)) {
7460 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7463 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7464 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7466 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7467 * first use
7469 return hr;
7472 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7474 /** FIXME: always true at the moment **/
7475 if(!bEnableDialogs) {
7476 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7478 return WINED3D_OK;
7482 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7483 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7484 TRACE("(%p) : pParameters %p\n", This, pParameters);
7486 *pParameters = This->createParms;
7487 return WINED3D_OK;
7490 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7491 IWineD3DSwapChain *swapchain;
7493 TRACE("Relaying to swapchain\n");
7495 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7496 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7497 IWineD3DSwapChain_Release(swapchain);
7499 return;
7502 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7503 IWineD3DSwapChain *swapchain;
7505 TRACE("Relaying to swapchain\n");
7507 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7508 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7509 IWineD3DSwapChain_Release(swapchain);
7511 return;
7515 /** ********************************************************
7516 * Notification functions
7517 ** ********************************************************/
7518 /** This function must be called in the release of a resource when ref == 0,
7519 * the contents of resource must still be correct,
7520 * any handles to other resource held by the caller must be closed
7521 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7522 *****************************************************/
7523 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7524 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7526 TRACE("(%p) : Adding Resource %p\n", This, resource);
7527 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7530 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7533 TRACE("(%p) : Removing resource %p\n", This, resource);
7535 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7539 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7540 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7541 int counter;
7543 TRACE("(%p) : resource %p\n", This, resource);
7544 switch(IWineD3DResource_GetType(resource)){
7545 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7546 case WINED3DRTYPE_SURFACE: {
7547 unsigned int i;
7549 /* Cleanup any FBO attachments if d3d is enabled */
7550 if(This->d3d_initialized) {
7551 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7552 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7554 TRACE("Last active render target destroyed\n");
7555 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7556 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7557 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7558 * and the lastActiveRenderTarget member shouldn't matter
7560 if(swapchain) {
7561 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7562 TRACE("Activating primary back buffer\n");
7563 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7564 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7565 /* Single buffering environment */
7566 TRACE("Activating primary front buffer\n");
7567 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7568 } else {
7569 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7570 /* Implicit render target destroyed, that means the device is being destroyed
7571 * whatever we set here, it shouldn't matter
7573 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7575 } else {
7576 /* May happen during ddraw uninitialization */
7577 TRACE("Render target set, but swapchain does not exist!\n");
7578 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7582 ENTER_GL();
7583 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7584 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7585 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7586 set_render_target_fbo(iface, i, NULL);
7587 This->fbo_color_attachments[i] = NULL;
7590 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7591 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7592 set_depth_stencil_fbo(iface, NULL);
7593 This->fbo_depth_attachment = NULL;
7595 LEAVE_GL();
7598 break;
7600 case WINED3DRTYPE_TEXTURE:
7601 case WINED3DRTYPE_CUBETEXTURE:
7602 case WINED3DRTYPE_VOLUMETEXTURE:
7603 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7604 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7605 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7606 This->stateBlock->textures[counter] = NULL;
7608 if (This->updateStateBlock != This->stateBlock ){
7609 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7610 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7611 This->updateStateBlock->textures[counter] = NULL;
7615 break;
7616 case WINED3DRTYPE_VOLUME:
7617 /* TODO: nothing really? */
7618 break;
7619 case WINED3DRTYPE_VERTEXBUFFER:
7620 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7622 int streamNumber;
7623 TRACE("Cleaning up stream pointers\n");
7625 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7626 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7627 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7629 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7630 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7631 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7632 This->updateStateBlock->streamSource[streamNumber] = 0;
7633 /* Set changed flag? */
7636 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) */
7637 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7638 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7639 This->stateBlock->streamSource[streamNumber] = 0;
7642 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7643 else { /* This shouldn't happen */
7644 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7646 #endif
7650 break;
7651 case WINED3DRTYPE_INDEXBUFFER:
7652 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7653 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7654 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7655 This->updateStateBlock->pIndexData = NULL;
7658 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7659 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7660 This->stateBlock->pIndexData = NULL;
7664 break;
7665 default:
7666 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7667 break;
7671 /* Remove the resource from the resourceStore */
7672 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7674 TRACE("Resource released\n");
7678 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7680 IWineD3DResourceImpl *resource, *cursor;
7681 HRESULT ret;
7682 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7684 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7685 TRACE("enumerating resource %p\n", resource);
7686 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7687 ret = pCallback((IWineD3DResource *) resource, pData);
7688 if(ret == S_FALSE) {
7689 TRACE("Canceling enumeration\n");
7690 break;
7693 return WINED3D_OK;
7696 /**********************************************************
7697 * IWineD3DDevice VTbl follows
7698 **********************************************************/
7700 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7702 /*** IUnknown methods ***/
7703 IWineD3DDeviceImpl_QueryInterface,
7704 IWineD3DDeviceImpl_AddRef,
7705 IWineD3DDeviceImpl_Release,
7706 /*** IWineD3DDevice methods ***/
7707 IWineD3DDeviceImpl_GetParent,
7708 /*** Creation methods**/
7709 IWineD3DDeviceImpl_CreateVertexBuffer,
7710 IWineD3DDeviceImpl_CreateIndexBuffer,
7711 IWineD3DDeviceImpl_CreateStateBlock,
7712 IWineD3DDeviceImpl_CreateSurface,
7713 IWineD3DDeviceImpl_CreateTexture,
7714 IWineD3DDeviceImpl_CreateVolumeTexture,
7715 IWineD3DDeviceImpl_CreateVolume,
7716 IWineD3DDeviceImpl_CreateCubeTexture,
7717 IWineD3DDeviceImpl_CreateQuery,
7718 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7719 IWineD3DDeviceImpl_CreateVertexDeclaration,
7720 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7721 IWineD3DDeviceImpl_CreateVertexShader,
7722 IWineD3DDeviceImpl_CreatePixelShader,
7723 IWineD3DDeviceImpl_CreatePalette,
7724 /*** Odd functions **/
7725 IWineD3DDeviceImpl_Init3D,
7726 IWineD3DDeviceImpl_InitGDI,
7727 IWineD3DDeviceImpl_Uninit3D,
7728 IWineD3DDeviceImpl_UninitGDI,
7729 IWineD3DDeviceImpl_SetMultithreaded,
7730 IWineD3DDeviceImpl_EvictManagedResources,
7731 IWineD3DDeviceImpl_GetAvailableTextureMem,
7732 IWineD3DDeviceImpl_GetBackBuffer,
7733 IWineD3DDeviceImpl_GetCreationParameters,
7734 IWineD3DDeviceImpl_GetDeviceCaps,
7735 IWineD3DDeviceImpl_GetDirect3D,
7736 IWineD3DDeviceImpl_GetDisplayMode,
7737 IWineD3DDeviceImpl_SetDisplayMode,
7738 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7739 IWineD3DDeviceImpl_GetRasterStatus,
7740 IWineD3DDeviceImpl_GetSwapChain,
7741 IWineD3DDeviceImpl_Reset,
7742 IWineD3DDeviceImpl_SetDialogBoxMode,
7743 IWineD3DDeviceImpl_SetCursorProperties,
7744 IWineD3DDeviceImpl_SetCursorPosition,
7745 IWineD3DDeviceImpl_ShowCursor,
7746 IWineD3DDeviceImpl_TestCooperativeLevel,
7747 /*** Getters and setters **/
7748 IWineD3DDeviceImpl_SetClipPlane,
7749 IWineD3DDeviceImpl_GetClipPlane,
7750 IWineD3DDeviceImpl_SetClipStatus,
7751 IWineD3DDeviceImpl_GetClipStatus,
7752 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7753 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7754 IWineD3DDeviceImpl_SetDepthStencilSurface,
7755 IWineD3DDeviceImpl_GetDepthStencilSurface,
7756 IWineD3DDeviceImpl_SetFVF,
7757 IWineD3DDeviceImpl_GetFVF,
7758 IWineD3DDeviceImpl_SetGammaRamp,
7759 IWineD3DDeviceImpl_GetGammaRamp,
7760 IWineD3DDeviceImpl_SetIndices,
7761 IWineD3DDeviceImpl_GetIndices,
7762 IWineD3DDeviceImpl_SetBaseVertexIndex,
7763 IWineD3DDeviceImpl_GetBaseVertexIndex,
7764 IWineD3DDeviceImpl_SetLight,
7765 IWineD3DDeviceImpl_GetLight,
7766 IWineD3DDeviceImpl_SetLightEnable,
7767 IWineD3DDeviceImpl_GetLightEnable,
7768 IWineD3DDeviceImpl_SetMaterial,
7769 IWineD3DDeviceImpl_GetMaterial,
7770 IWineD3DDeviceImpl_SetNPatchMode,
7771 IWineD3DDeviceImpl_GetNPatchMode,
7772 IWineD3DDeviceImpl_SetPaletteEntries,
7773 IWineD3DDeviceImpl_GetPaletteEntries,
7774 IWineD3DDeviceImpl_SetPixelShader,
7775 IWineD3DDeviceImpl_GetPixelShader,
7776 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7777 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7778 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7779 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7780 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7781 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7782 IWineD3DDeviceImpl_SetRenderState,
7783 IWineD3DDeviceImpl_GetRenderState,
7784 IWineD3DDeviceImpl_SetRenderTarget,
7785 IWineD3DDeviceImpl_GetRenderTarget,
7786 IWineD3DDeviceImpl_SetFrontBackBuffers,
7787 IWineD3DDeviceImpl_SetSamplerState,
7788 IWineD3DDeviceImpl_GetSamplerState,
7789 IWineD3DDeviceImpl_SetScissorRect,
7790 IWineD3DDeviceImpl_GetScissorRect,
7791 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7792 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7793 IWineD3DDeviceImpl_SetStreamSource,
7794 IWineD3DDeviceImpl_GetStreamSource,
7795 IWineD3DDeviceImpl_SetStreamSourceFreq,
7796 IWineD3DDeviceImpl_GetStreamSourceFreq,
7797 IWineD3DDeviceImpl_SetTexture,
7798 IWineD3DDeviceImpl_GetTexture,
7799 IWineD3DDeviceImpl_SetTextureStageState,
7800 IWineD3DDeviceImpl_GetTextureStageState,
7801 IWineD3DDeviceImpl_SetTransform,
7802 IWineD3DDeviceImpl_GetTransform,
7803 IWineD3DDeviceImpl_SetVertexDeclaration,
7804 IWineD3DDeviceImpl_GetVertexDeclaration,
7805 IWineD3DDeviceImpl_SetVertexShader,
7806 IWineD3DDeviceImpl_GetVertexShader,
7807 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7808 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7809 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7810 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7811 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7812 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7813 IWineD3DDeviceImpl_SetViewport,
7814 IWineD3DDeviceImpl_GetViewport,
7815 IWineD3DDeviceImpl_MultiplyTransform,
7816 IWineD3DDeviceImpl_ValidateDevice,
7817 IWineD3DDeviceImpl_ProcessVertices,
7818 /*** State block ***/
7819 IWineD3DDeviceImpl_BeginStateBlock,
7820 IWineD3DDeviceImpl_EndStateBlock,
7821 /*** Scene management ***/
7822 IWineD3DDeviceImpl_BeginScene,
7823 IWineD3DDeviceImpl_EndScene,
7824 IWineD3DDeviceImpl_Present,
7825 IWineD3DDeviceImpl_Clear,
7826 /*** Drawing ***/
7827 IWineD3DDeviceImpl_DrawPrimitive,
7828 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7829 IWineD3DDeviceImpl_DrawPrimitiveUP,
7830 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7831 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7832 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7833 IWineD3DDeviceImpl_DrawRectPatch,
7834 IWineD3DDeviceImpl_DrawTriPatch,
7835 IWineD3DDeviceImpl_DeletePatch,
7836 IWineD3DDeviceImpl_ColorFill,
7837 IWineD3DDeviceImpl_UpdateTexture,
7838 IWineD3DDeviceImpl_UpdateSurface,
7839 IWineD3DDeviceImpl_GetFrontBufferData,
7840 /*** object tracking ***/
7841 IWineD3DDeviceImpl_ResourceReleased,
7842 IWineD3DDeviceImpl_EnumResources
7845 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7847 /*** IUnknown methods ***/
7848 IWineD3DDeviceImpl_QueryInterface,
7849 IWineD3DDeviceImpl_AddRef,
7850 IWineD3DDeviceImpl_Release,
7851 /*** IWineD3DDevice methods ***/
7852 IWineD3DDeviceImpl_GetParent,
7853 /*** Creation methods**/
7854 IWineD3DDeviceImpl_CreateVertexBuffer,
7855 IWineD3DDeviceImpl_CreateIndexBuffer,
7856 IWineD3DDeviceImpl_CreateStateBlock,
7857 IWineD3DDeviceImpl_CreateSurface,
7858 IWineD3DDeviceImpl_CreateTexture,
7859 IWineD3DDeviceImpl_CreateVolumeTexture,
7860 IWineD3DDeviceImpl_CreateVolume,
7861 IWineD3DDeviceImpl_CreateCubeTexture,
7862 IWineD3DDeviceImpl_CreateQuery,
7863 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7864 IWineD3DDeviceImpl_CreateVertexDeclaration,
7865 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7866 IWineD3DDeviceImpl_CreateVertexShader,
7867 IWineD3DDeviceImpl_CreatePixelShader,
7868 IWineD3DDeviceImpl_CreatePalette,
7869 /*** Odd functions **/
7870 IWineD3DDeviceImpl_Init3D,
7871 IWineD3DDeviceImpl_InitGDI,
7872 IWineD3DDeviceImpl_Uninit3D,
7873 IWineD3DDeviceImpl_UninitGDI,
7874 IWineD3DDeviceImpl_SetMultithreaded,
7875 IWineD3DDeviceImpl_EvictManagedResources,
7876 IWineD3DDeviceImpl_GetAvailableTextureMem,
7877 IWineD3DDeviceImpl_GetBackBuffer,
7878 IWineD3DDeviceImpl_GetCreationParameters,
7879 IWineD3DDeviceImpl_GetDeviceCaps,
7880 IWineD3DDeviceImpl_GetDirect3D,
7881 IWineD3DDeviceImpl_GetDisplayMode,
7882 IWineD3DDeviceImpl_SetDisplayMode,
7883 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7884 IWineD3DDeviceImpl_GetRasterStatus,
7885 IWineD3DDeviceImpl_GetSwapChain,
7886 IWineD3DDeviceImpl_Reset,
7887 IWineD3DDeviceImpl_SetDialogBoxMode,
7888 IWineD3DDeviceImpl_SetCursorProperties,
7889 IWineD3DDeviceImpl_SetCursorPosition,
7890 IWineD3DDeviceImpl_ShowCursor,
7891 IWineD3DDeviceImpl_TestCooperativeLevel,
7892 /*** Getters and setters **/
7893 IWineD3DDeviceImpl_SetClipPlane,
7894 IWineD3DDeviceImpl_GetClipPlane,
7895 IWineD3DDeviceImpl_SetClipStatus,
7896 IWineD3DDeviceImpl_GetClipStatus,
7897 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7898 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7899 IWineD3DDeviceImpl_SetDepthStencilSurface,
7900 IWineD3DDeviceImpl_GetDepthStencilSurface,
7901 IWineD3DDeviceImpl_SetFVF,
7902 IWineD3DDeviceImpl_GetFVF,
7903 IWineD3DDeviceImpl_SetGammaRamp,
7904 IWineD3DDeviceImpl_GetGammaRamp,
7905 IWineD3DDeviceImpl_SetIndices,
7906 IWineD3DDeviceImpl_GetIndices,
7907 IWineD3DDeviceImpl_SetBaseVertexIndex,
7908 IWineD3DDeviceImpl_GetBaseVertexIndex,
7909 IWineD3DDeviceImpl_SetLight,
7910 IWineD3DDeviceImpl_GetLight,
7911 IWineD3DDeviceImpl_SetLightEnable,
7912 IWineD3DDeviceImpl_GetLightEnable,
7913 IWineD3DDeviceImpl_SetMaterial,
7914 IWineD3DDeviceImpl_GetMaterial,
7915 IWineD3DDeviceImpl_SetNPatchMode,
7916 IWineD3DDeviceImpl_GetNPatchMode,
7917 IWineD3DDeviceImpl_SetPaletteEntries,
7918 IWineD3DDeviceImpl_GetPaletteEntries,
7919 IWineD3DDeviceImpl_SetPixelShader,
7920 IWineD3DDeviceImpl_GetPixelShader,
7921 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7922 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7923 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7924 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7925 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7926 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7927 IWineD3DDeviceImpl_SetRenderState,
7928 IWineD3DDeviceImpl_GetRenderState,
7929 IWineD3DDeviceImpl_SetRenderTarget,
7930 IWineD3DDeviceImpl_GetRenderTarget,
7931 IWineD3DDeviceImpl_SetFrontBackBuffers,
7932 IWineD3DDeviceImpl_SetSamplerState,
7933 IWineD3DDeviceImpl_GetSamplerState,
7934 IWineD3DDeviceImpl_SetScissorRect,
7935 IWineD3DDeviceImpl_GetScissorRect,
7936 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7937 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7938 IWineD3DDeviceImpl_SetStreamSource,
7939 IWineD3DDeviceImpl_GetStreamSource,
7940 IWineD3DDeviceImpl_SetStreamSourceFreq,
7941 IWineD3DDeviceImpl_GetStreamSourceFreq,
7942 IWineD3DDeviceImpl_SetTexture,
7943 IWineD3DDeviceImpl_GetTexture,
7944 IWineD3DDeviceImpl_SetTextureStageState,
7945 IWineD3DDeviceImpl_GetTextureStageState,
7946 IWineD3DDeviceImpl_SetTransform,
7947 IWineD3DDeviceImpl_GetTransform,
7948 IWineD3DDeviceImpl_SetVertexDeclaration,
7949 IWineD3DDeviceImpl_GetVertexDeclaration,
7950 IWineD3DDeviceImpl_SetVertexShader,
7951 IWineD3DDeviceImpl_GetVertexShader,
7952 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7953 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7954 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7955 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7956 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7957 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7958 IWineD3DDeviceImpl_SetViewport,
7959 IWineD3DDeviceImpl_GetViewport,
7960 IWineD3DDeviceImpl_MultiplyTransform,
7961 IWineD3DDeviceImpl_ValidateDevice,
7962 IWineD3DDeviceImpl_ProcessVertices,
7963 /*** State block ***/
7964 IWineD3DDeviceImpl_BeginStateBlock,
7965 IWineD3DDeviceImpl_EndStateBlock,
7966 /*** Scene management ***/
7967 IWineD3DDeviceImpl_BeginScene,
7968 IWineD3DDeviceImpl_EndScene,
7969 IWineD3DDeviceImpl_Present,
7970 IWineD3DDeviceImpl_Clear,
7971 /*** Drawing ***/
7972 IWineD3DDeviceImpl_DrawPrimitive,
7973 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7974 IWineD3DDeviceImpl_DrawPrimitiveUP,
7975 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7976 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7977 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7978 IWineD3DDeviceImpl_DrawRectPatch,
7979 IWineD3DDeviceImpl_DrawTriPatch,
7980 IWineD3DDeviceImpl_DeletePatch,
7981 IWineD3DDeviceImpl_ColorFill,
7982 IWineD3DDeviceImpl_UpdateTexture,
7983 IWineD3DDeviceImpl_UpdateSurface,
7984 IWineD3DDeviceImpl_GetFrontBufferData,
7985 /*** object tracking ***/
7986 IWineD3DDeviceImpl_ResourceReleased,
7987 IWineD3DDeviceImpl_EnumResources
7990 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7991 WINED3DRS_ALPHABLENDENABLE ,
7992 WINED3DRS_ALPHAFUNC ,
7993 WINED3DRS_ALPHAREF ,
7994 WINED3DRS_ALPHATESTENABLE ,
7995 WINED3DRS_BLENDOP ,
7996 WINED3DRS_COLORWRITEENABLE ,
7997 WINED3DRS_DESTBLEND ,
7998 WINED3DRS_DITHERENABLE ,
7999 WINED3DRS_FILLMODE ,
8000 WINED3DRS_FOGDENSITY ,
8001 WINED3DRS_FOGEND ,
8002 WINED3DRS_FOGSTART ,
8003 WINED3DRS_LASTPIXEL ,
8004 WINED3DRS_SHADEMODE ,
8005 WINED3DRS_SRCBLEND ,
8006 WINED3DRS_STENCILENABLE ,
8007 WINED3DRS_STENCILFAIL ,
8008 WINED3DRS_STENCILFUNC ,
8009 WINED3DRS_STENCILMASK ,
8010 WINED3DRS_STENCILPASS ,
8011 WINED3DRS_STENCILREF ,
8012 WINED3DRS_STENCILWRITEMASK ,
8013 WINED3DRS_STENCILZFAIL ,
8014 WINED3DRS_TEXTUREFACTOR ,
8015 WINED3DRS_WRAP0 ,
8016 WINED3DRS_WRAP1 ,
8017 WINED3DRS_WRAP2 ,
8018 WINED3DRS_WRAP3 ,
8019 WINED3DRS_WRAP4 ,
8020 WINED3DRS_WRAP5 ,
8021 WINED3DRS_WRAP6 ,
8022 WINED3DRS_WRAP7 ,
8023 WINED3DRS_ZENABLE ,
8024 WINED3DRS_ZFUNC ,
8025 WINED3DRS_ZWRITEENABLE
8028 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8029 WINED3DTSS_ADDRESSW ,
8030 WINED3DTSS_ALPHAARG0 ,
8031 WINED3DTSS_ALPHAARG1 ,
8032 WINED3DTSS_ALPHAARG2 ,
8033 WINED3DTSS_ALPHAOP ,
8034 WINED3DTSS_BUMPENVLOFFSET ,
8035 WINED3DTSS_BUMPENVLSCALE ,
8036 WINED3DTSS_BUMPENVMAT00 ,
8037 WINED3DTSS_BUMPENVMAT01 ,
8038 WINED3DTSS_BUMPENVMAT10 ,
8039 WINED3DTSS_BUMPENVMAT11 ,
8040 WINED3DTSS_COLORARG0 ,
8041 WINED3DTSS_COLORARG1 ,
8042 WINED3DTSS_COLORARG2 ,
8043 WINED3DTSS_COLOROP ,
8044 WINED3DTSS_RESULTARG ,
8045 WINED3DTSS_TEXCOORDINDEX ,
8046 WINED3DTSS_TEXTURETRANSFORMFLAGS
8049 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8050 WINED3DSAMP_ADDRESSU ,
8051 WINED3DSAMP_ADDRESSV ,
8052 WINED3DSAMP_ADDRESSW ,
8053 WINED3DSAMP_BORDERCOLOR ,
8054 WINED3DSAMP_MAGFILTER ,
8055 WINED3DSAMP_MINFILTER ,
8056 WINED3DSAMP_MIPFILTER ,
8057 WINED3DSAMP_MIPMAPLODBIAS ,
8058 WINED3DSAMP_MAXMIPLEVEL ,
8059 WINED3DSAMP_MAXANISOTROPY ,
8060 WINED3DSAMP_SRGBTEXTURE ,
8061 WINED3DSAMP_ELEMENTINDEX
8064 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8065 WINED3DRS_AMBIENT ,
8066 WINED3DRS_AMBIENTMATERIALSOURCE ,
8067 WINED3DRS_CLIPPING ,
8068 WINED3DRS_CLIPPLANEENABLE ,
8069 WINED3DRS_COLORVERTEX ,
8070 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8071 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8072 WINED3DRS_FOGDENSITY ,
8073 WINED3DRS_FOGEND ,
8074 WINED3DRS_FOGSTART ,
8075 WINED3DRS_FOGTABLEMODE ,
8076 WINED3DRS_FOGVERTEXMODE ,
8077 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8078 WINED3DRS_LIGHTING ,
8079 WINED3DRS_LOCALVIEWER ,
8080 WINED3DRS_MULTISAMPLEANTIALIAS ,
8081 WINED3DRS_MULTISAMPLEMASK ,
8082 WINED3DRS_NORMALIZENORMALS ,
8083 WINED3DRS_PATCHEDGESTYLE ,
8084 WINED3DRS_POINTSCALE_A ,
8085 WINED3DRS_POINTSCALE_B ,
8086 WINED3DRS_POINTSCALE_C ,
8087 WINED3DRS_POINTSCALEENABLE ,
8088 WINED3DRS_POINTSIZE ,
8089 WINED3DRS_POINTSIZE_MAX ,
8090 WINED3DRS_POINTSIZE_MIN ,
8091 WINED3DRS_POINTSPRITEENABLE ,
8092 WINED3DRS_RANGEFOGENABLE ,
8093 WINED3DRS_SPECULARMATERIALSOURCE ,
8094 WINED3DRS_TWEENFACTOR ,
8095 WINED3DRS_VERTEXBLEND ,
8096 WINED3DRS_CULLMODE ,
8097 WINED3DRS_FOGCOLOR
8100 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8101 WINED3DTSS_TEXCOORDINDEX ,
8102 WINED3DTSS_TEXTURETRANSFORMFLAGS
8105 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8106 WINED3DSAMP_DMAPOFFSET
8109 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8110 DWORD rep = This->StateTable[state].representative;
8111 DWORD idx;
8112 BYTE shift;
8113 UINT i;
8114 WineD3DContext *context;
8116 if(!rep) return;
8117 for(i = 0; i < This->numContexts; i++) {
8118 context = This->contexts[i];
8119 if(isStateDirty(context, rep)) continue;
8121 context->dirtyArray[context->numDirtyEntries++] = rep;
8122 idx = rep >> 5;
8123 shift = rep & 0x1f;
8124 context->isStateDirty[idx] |= (1 << shift);
8128 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8129 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8130 /* The drawable size of a pbuffer render target is the current pbuffer size
8132 *width = dev->pbufferWidth;
8133 *height = dev->pbufferHeight;
8136 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8137 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8139 *width = This->pow2Width;
8140 *height = This->pow2Height;
8143 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8144 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8145 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8146 * current context's drawable, which is the size of the back buffer of the swapchain
8147 * the active context belongs to. The back buffer of the swapchain is stored as the
8148 * surface the context belongs to.
8150 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8151 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;