push e263afdf8dbf9f9408e8594e045d25c4af1d55cd
[wine/hacks.git] / dlls / wined3d / device.c
blob6577015697f0e674a14f98e60b9a9f2d3d7898ba
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(vshader_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(vshader_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 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
646 } else {
647 /* The pitch is a multiple of 4 bytes */
648 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
649 Size *= Height;
652 /** Create and initialise the surface resource **/
653 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
654 /* "Standalone" surface */
655 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
657 object->currentDesc.Width = Width;
658 object->currentDesc.Height = Height;
659 object->currentDesc.MultiSampleType = MultiSample;
660 object->currentDesc.MultiSampleQuality = MultisampleQuality;
661 object->glDescription.level = Level;
663 /* Flags */
664 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
665 object->Flags |= Discard ? SFLAG_DISCARD : 0;
666 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
667 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
670 if (WINED3DFMT_UNKNOWN != Format) {
671 object->bytesPerPixel = tableEntry->bpp;
672 } else {
673 object->bytesPerPixel = 0;
676 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
678 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
680 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
681 * this function is too deep to need to care about things like this.
682 * Levels need to be checked too, and possibly Type since they all affect what can be done.
683 * ****************************************/
684 switch(Pool) {
685 case WINED3DPOOL_SCRATCH:
686 if(!Lockable)
687 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
688 "which are mutually exclusive, setting lockable to TRUE\n");
689 Lockable = TRUE;
690 break;
691 case WINED3DPOOL_SYSTEMMEM:
692 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
693 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
694 case WINED3DPOOL_MANAGED:
695 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
696 "Usage of DYNAMIC which are mutually exclusive, not doing "
697 "anything just telling you.\n");
698 break;
699 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
700 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
701 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
702 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
703 break;
704 default:
705 FIXME("(%p) Unknown pool %d\n", This, Pool);
706 break;
709 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
710 FIXME("Trying to create a render target that isn't in the default pool\n");
713 /* mark the texture as dirty so that it gets loaded first time around*/
714 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
715 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
716 This, Width, Height, Format, debug_d3dformat(Format),
717 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
719 /* Store the DirectDraw primary surface. This is the first rendertarget surface created */
720 if( (Usage & WINED3DUSAGE_RENDERTARGET) && (!This->ddraw_primary) )
721 This->ddraw_primary = (IWineD3DSurface *) object;
723 /* Look at the implementation and set the correct Vtable */
724 switch(Impl) {
725 case SURFACE_OPENGL:
726 /* Check if a 3D adapter is available when creating gl surfaces */
727 if(!This->adapter) {
728 ERR("OpenGL surfaces are not available without opengl\n");
729 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
730 HeapFree(GetProcessHeap(), 0, object);
731 return WINED3DERR_NOTAVAILABLE;
733 break;
735 case SURFACE_GDI:
736 object->lpVtbl = &IWineGDISurface_Vtbl;
737 break;
739 default:
740 /* To be sure to catch this */
741 ERR("Unknown requested surface implementation %d!\n", Impl);
742 IWineD3DSurface_Release((IWineD3DSurface *) object);
743 return WINED3DERR_INVALIDCALL;
746 list_init(&object->renderbuffers);
748 /* Call the private setup routine */
749 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
753 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
754 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
755 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
756 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
758 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
759 IWineD3DTextureImpl *object;
760 unsigned int i;
761 UINT tmpW;
762 UINT tmpH;
763 HRESULT hr;
764 unsigned int pow2Width;
765 unsigned int pow2Height;
766 const GlPixelFormatDesc *glDesc;
767 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
769 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
770 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
771 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
773 /* TODO: It should only be possible to create textures for formats
774 that are reported as supported */
775 if (WINED3DFMT_UNKNOWN >= Format) {
776 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
777 return WINED3DERR_INVALIDCALL;
780 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
781 D3DINITIALIZEBASETEXTURE(object->baseTexture);
782 object->width = Width;
783 object->height = Height;
785 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
786 object->baseTexture.minMipLookup = &minMipLookup;
787 object->baseTexture.magLookup = &magLookup;
788 } else {
789 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
790 object->baseTexture.magLookup = &magLookup_noFilter;
793 /** Non-power2 support **/
794 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
795 pow2Width = Width;
796 pow2Height = Height;
797 } else {
798 /* Find the nearest pow2 match */
799 pow2Width = pow2Height = 1;
800 while (pow2Width < Width) pow2Width <<= 1;
801 while (pow2Height < Height) pow2Height <<= 1;
803 if(pow2Width != Width || pow2Height != Height) {
804 if(Levels > 1) {
805 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
806 HeapFree(GetProcessHeap(), 0, object);
807 *ppTexture = NULL;
808 return WINED3DERR_INVALIDCALL;
809 } else {
810 Levels = 1;
815 /** FIXME: add support for real non-power-two if it's provided by the video card **/
816 /* Precalculated scaling for 'faked' non power of two texture coords.
817 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
818 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
819 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
821 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
822 object->baseTexture.pow2Matrix[0] = 1.0;
823 object->baseTexture.pow2Matrix[5] = 1.0;
824 object->baseTexture.pow2Matrix[10] = 1.0;
825 object->baseTexture.pow2Matrix[15] = 1.0;
826 object->target = GL_TEXTURE_2D;
827 object->cond_np2 = TRUE;
828 pow2Width = Width;
829 pow2Height = Height;
830 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
831 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
832 (Width != pow2Width || Height != pow2Height) &&
833 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
835 object->baseTexture.pow2Matrix[0] = (float)Width;
836 object->baseTexture.pow2Matrix[5] = (float)Height;
837 object->baseTexture.pow2Matrix[10] = 1.0;
838 object->baseTexture.pow2Matrix[15] = 1.0;
839 object->target = GL_TEXTURE_RECTANGLE_ARB;
840 object->cond_np2 = TRUE;
841 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
842 } else {
843 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
844 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
845 object->baseTexture.pow2Matrix[10] = 1.0;
846 object->baseTexture.pow2Matrix[15] = 1.0;
847 object->target = GL_TEXTURE_2D;
848 object->cond_np2 = FALSE;
850 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
852 /* Calculate levels for mip mapping */
853 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
854 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
855 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
856 return WINED3DERR_INVALIDCALL;
858 if(Levels > 1) {
859 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
860 return WINED3DERR_INVALIDCALL;
862 object->baseTexture.levels = 1;
863 } else if (Levels == 0) {
864 TRACE("calculating levels %d\n", object->baseTexture.levels);
865 object->baseTexture.levels++;
866 tmpW = Width;
867 tmpH = Height;
868 while (tmpW > 1 || tmpH > 1) {
869 tmpW = max(1, tmpW >> 1);
870 tmpH = max(1, tmpH >> 1);
871 object->baseTexture.levels++;
873 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
876 /* Generate all the surfaces */
877 tmpW = Width;
878 tmpH = Height;
879 for (i = 0; i < object->baseTexture.levels; i++)
881 /* use the callback to create the texture surface */
882 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
883 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
884 FIXME("Failed to create surface %p\n", object);
885 /* clean up */
886 object->surfaces[i] = NULL;
887 IWineD3DTexture_Release((IWineD3DTexture *)object);
889 *ppTexture = NULL;
890 return hr;
893 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
894 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
895 /* calculate the next mipmap level */
896 tmpW = max(1, tmpW >> 1);
897 tmpH = max(1, tmpH >> 1);
899 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
901 TRACE("(%p) : Created texture %p\n", This, object);
902 return WINED3D_OK;
905 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
906 UINT Width, UINT Height, UINT Depth,
907 UINT Levels, DWORD Usage,
908 WINED3DFORMAT Format, WINED3DPOOL Pool,
909 IWineD3DVolumeTexture **ppVolumeTexture,
910 HANDLE *pSharedHandle, IUnknown *parent,
911 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
913 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
914 IWineD3DVolumeTextureImpl *object;
915 unsigned int i;
916 UINT tmpW;
917 UINT tmpH;
918 UINT tmpD;
919 const GlPixelFormatDesc *glDesc;
921 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
923 /* TODO: It should only be possible to create textures for formats
924 that are reported as supported */
925 if (WINED3DFMT_UNKNOWN >= Format) {
926 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
927 return WINED3DERR_INVALIDCALL;
929 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
930 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
931 return WINED3DERR_INVALIDCALL;
934 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
935 D3DINITIALIZEBASETEXTURE(object->baseTexture);
937 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
938 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
940 object->width = Width;
941 object->height = Height;
942 object->depth = Depth;
944 /* Is NP2 support for volumes needed? */
945 object->baseTexture.pow2Matrix[ 0] = 1.0;
946 object->baseTexture.pow2Matrix[ 5] = 1.0;
947 object->baseTexture.pow2Matrix[10] = 1.0;
948 object->baseTexture.pow2Matrix[15] = 1.0;
950 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
951 object->baseTexture.minMipLookup = &minMipLookup;
952 object->baseTexture.magLookup = &magLookup;
953 } else {
954 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
955 object->baseTexture.magLookup = &magLookup_noFilter;
958 /* Calculate levels for mip mapping */
959 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
960 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
961 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
962 return WINED3DERR_INVALIDCALL;
964 if(Levels > 1) {
965 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
966 return WINED3DERR_INVALIDCALL;
968 Levels = 1;
969 } else if (Levels == 0) {
970 object->baseTexture.levels++;
971 tmpW = Width;
972 tmpH = Height;
973 tmpD = Depth;
974 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
975 tmpW = max(1, tmpW >> 1);
976 tmpH = max(1, tmpH >> 1);
977 tmpD = max(1, tmpD >> 1);
978 object->baseTexture.levels++;
980 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
983 /* Generate all the surfaces */
984 tmpW = Width;
985 tmpH = Height;
986 tmpD = Depth;
988 for (i = 0; i < object->baseTexture.levels; i++)
990 HRESULT hr;
991 /* Create the volume */
992 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
993 &object->volumes[i], pSharedHandle);
995 if(FAILED(hr)) {
996 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
997 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
998 *ppVolumeTexture = NULL;
999 return hr;
1002 /* Set its container to this object */
1003 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1005 /* calculate the next mipmap level */
1006 tmpW = max(1, tmpW >> 1);
1007 tmpH = max(1, tmpH >> 1);
1008 tmpD = max(1, tmpD >> 1);
1010 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1012 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1013 TRACE("(%p) : Created volume texture %p\n", This, object);
1014 return WINED3D_OK;
1017 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1018 UINT Width, UINT Height, UINT Depth,
1019 DWORD Usage,
1020 WINED3DFORMAT Format, WINED3DPOOL Pool,
1021 IWineD3DVolume** ppVolume,
1022 HANDLE* pSharedHandle, IUnknown *parent) {
1024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1025 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1026 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1028 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1029 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1030 return WINED3DERR_INVALIDCALL;
1033 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1035 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1036 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1038 object->currentDesc.Width = Width;
1039 object->currentDesc.Height = Height;
1040 object->currentDesc.Depth = Depth;
1041 object->bytesPerPixel = formatDesc->bpp;
1043 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1044 object->lockable = TRUE;
1045 object->locked = FALSE;
1046 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1047 object->dirty = TRUE;
1049 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1052 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1053 UINT Levels, DWORD Usage,
1054 WINED3DFORMAT Format, WINED3DPOOL Pool,
1055 IWineD3DCubeTexture **ppCubeTexture,
1056 HANDLE *pSharedHandle, IUnknown *parent,
1057 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1059 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1060 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1061 unsigned int i, j;
1062 UINT tmpW;
1063 HRESULT hr;
1064 unsigned int pow2EdgeLength = EdgeLength;
1065 const GlPixelFormatDesc *glDesc;
1066 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1068 /* TODO: It should only be possible to create textures for formats
1069 that are reported as supported */
1070 if (WINED3DFMT_UNKNOWN >= Format) {
1071 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1072 return WINED3DERR_INVALIDCALL;
1075 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1076 WARN("(%p) : Tried to create not supported cube texture\n", This);
1077 return WINED3DERR_INVALIDCALL;
1080 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1081 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1083 TRACE("(%p) Create Cube Texture\n", This);
1085 /** Non-power2 support **/
1087 /* Find the nearest pow2 match */
1088 pow2EdgeLength = 1;
1089 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1091 object->edgeLength = EdgeLength;
1092 /* TODO: support for native non-power 2 */
1093 /* Precalculated scaling for 'faked' non power of two texture coords */
1094 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1095 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1096 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1097 object->baseTexture.pow2Matrix[15] = 1.0;
1099 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1100 object->baseTexture.minMipLookup = &minMipLookup;
1101 object->baseTexture.magLookup = &magLookup;
1102 } else {
1103 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1104 object->baseTexture.magLookup = &magLookup_noFilter;
1107 /* Calculate levels for mip mapping */
1108 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1109 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1110 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1111 HeapFree(GetProcessHeap(), 0, object);
1112 *ppCubeTexture = NULL;
1114 return WINED3DERR_INVALIDCALL;
1116 if(Levels > 1) {
1117 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1118 HeapFree(GetProcessHeap(), 0, object);
1119 *ppCubeTexture = NULL;
1121 return WINED3DERR_INVALIDCALL;
1123 Levels = 1;
1124 } else if (Levels == 0) {
1125 object->baseTexture.levels++;
1126 tmpW = EdgeLength;
1127 while (tmpW > 1) {
1128 tmpW = max(1, tmpW >> 1);
1129 object->baseTexture.levels++;
1131 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1134 /* Generate all the surfaces */
1135 tmpW = EdgeLength;
1136 for (i = 0; i < object->baseTexture.levels; i++) {
1138 /* Create the 6 faces */
1139 for (j = 0; j < 6; j++) {
1141 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1142 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1144 if(hr!= WINED3D_OK) {
1145 /* clean up */
1146 int k;
1147 int l;
1148 for (l = 0; l < j; l++) {
1149 IWineD3DSurface_Release(object->surfaces[l][i]);
1151 for (k = 0; k < i; k++) {
1152 for (l = 0; l < 6; l++) {
1153 IWineD3DSurface_Release(object->surfaces[l][k]);
1157 FIXME("(%p) Failed to create surface\n",object);
1158 HeapFree(GetProcessHeap(),0,object);
1159 *ppCubeTexture = NULL;
1160 return hr;
1162 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1163 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1165 tmpW = max(1, tmpW >> 1);
1167 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1169 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1170 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1171 return WINED3D_OK;
1174 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1176 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1177 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1178 const IWineD3DQueryVtbl *vtable;
1180 /* Just a check to see if we support this type of query */
1181 switch(Type) {
1182 case WINED3DQUERYTYPE_OCCLUSION:
1183 TRACE("(%p) occlusion query\n", This);
1184 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1185 hr = WINED3D_OK;
1186 else
1187 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1189 vtable = &IWineD3DOcclusionQuery_Vtbl;
1190 break;
1192 case WINED3DQUERYTYPE_EVENT:
1193 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1194 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1195 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1197 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1199 vtable = &IWineD3DEventQuery_Vtbl;
1200 hr = WINED3D_OK;
1201 break;
1203 case WINED3DQUERYTYPE_VCACHE:
1204 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1205 case WINED3DQUERYTYPE_VERTEXSTATS:
1206 case WINED3DQUERYTYPE_TIMESTAMP:
1207 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1208 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1209 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1210 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1211 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1212 case WINED3DQUERYTYPE_PIXELTIMINGS:
1213 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1214 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1215 default:
1216 /* Use the base Query vtable until we have a special one for each query */
1217 vtable = &IWineD3DQuery_Vtbl;
1218 FIXME("(%p) Unhandled query type %d\n", This, Type);
1220 if(NULL == ppQuery || hr != WINED3D_OK) {
1221 return hr;
1224 D3DCREATEOBJECTINSTANCE(object, Query)
1225 object->lpVtbl = vtable;
1226 object->type = Type;
1227 object->state = QUERY_CREATED;
1228 /* allocated the 'extended' data based on the type of query requested */
1229 switch(Type){
1230 case WINED3DQUERYTYPE_OCCLUSION:
1231 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1232 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1234 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1235 TRACE("(%p) Allocating data for an occlusion query\n", This);
1236 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1237 break;
1239 case WINED3DQUERYTYPE_EVENT:
1240 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1241 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1243 if(GL_SUPPORT(APPLE_FENCE)) {
1244 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1245 checkGLcall("glGenFencesAPPLE");
1246 } else if(GL_SUPPORT(NV_FENCE)) {
1247 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1248 checkGLcall("glGenFencesNV");
1250 break;
1252 case WINED3DQUERYTYPE_VCACHE:
1253 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1254 case WINED3DQUERYTYPE_VERTEXSTATS:
1255 case WINED3DQUERYTYPE_TIMESTAMP:
1256 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1257 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1258 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1259 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1260 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1261 case WINED3DQUERYTYPE_PIXELTIMINGS:
1262 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1263 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1264 default:
1265 object->extendedData = 0;
1266 FIXME("(%p) Unhandled query type %d\n",This , Type);
1268 TRACE("(%p) : Created Query %p\n", This, object);
1269 return WINED3D_OK;
1272 /*****************************************************************************
1273 * IWineD3DDeviceImpl_SetupFullscreenWindow
1275 * Helper function that modifies a HWND's Style and ExStyle for proper
1276 * fullscreen use.
1278 * Params:
1279 * iface: Pointer to the IWineD3DDevice interface
1280 * window: Window to setup
1282 *****************************************************************************/
1283 static LONG fullscreen_style(LONG orig_style) {
1284 LONG style = orig_style;
1285 style &= ~WS_CAPTION;
1286 style &= ~WS_THICKFRAME;
1288 /* Make sure the window is managed, otherwise we won't get keyboard input */
1289 style |= WS_POPUP | WS_SYSMENU;
1291 return style;
1294 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1295 LONG exStyle = orig_exStyle;
1297 /* Filter out window decorations */
1298 exStyle &= ~WS_EX_WINDOWEDGE;
1299 exStyle &= ~WS_EX_CLIENTEDGE;
1301 return exStyle;
1304 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window) {
1305 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1307 LONG style, exStyle;
1308 /* Don't do anything if an original style is stored.
1309 * That shouldn't happen
1311 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1312 if (This->style || This->exStyle) {
1313 ERR("(%p): Want to change the window parameters of HWND %p, but "
1314 "another style is stored for restoration afterwards\n", This, window);
1317 /* Get the parameters and save them */
1318 style = GetWindowLongW(window, GWL_STYLE);
1319 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1320 This->style = style;
1321 This->exStyle = exStyle;
1323 style = fullscreen_style(style);
1324 exStyle = fullscreen_exStyle(exStyle);
1326 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1327 This->style, This->exStyle, style, exStyle);
1329 SetWindowLongW(window, GWL_STYLE, style);
1330 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1332 /* Inform the window about the update. */
1333 SetWindowPos(window, HWND_TOP, 0, 0,
1334 This->ddraw_width, This->ddraw_height, SWP_FRAMECHANGED);
1335 ShowWindow(window, SW_NORMAL);
1338 /*****************************************************************************
1339 * IWineD3DDeviceImpl_RestoreWindow
1341 * Helper function that restores a windows' properties when taking it out
1342 * of fullscreen mode
1344 * Params:
1345 * iface: Pointer to the IWineD3DDevice interface
1346 * window: Window to setup
1348 *****************************************************************************/
1349 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1350 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1351 LONG style, exStyle;
1353 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1354 * switch, do nothing
1356 if (!This->style && !This->exStyle) return;
1358 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1359 This, window, This->style, This->exStyle);
1361 style = GetWindowLongW(window, GWL_STYLE);
1362 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1364 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1365 * Some applications change it before calling Reset() when switching between windowed and
1366 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1368 if(style == fullscreen_style(This->style) &&
1369 exStyle == fullscreen_style(This->exStyle)) {
1370 SetWindowLongW(window, GWL_STYLE, This->style);
1371 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1374 /* Delete the old values */
1375 This->style = 0;
1376 This->exStyle = 0;
1378 /* Inform the window about the update */
1379 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1380 0, 0, 0, 0, /* Pos, Size, ignored */
1381 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1384 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1385 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1386 IUnknown* parent,
1387 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1388 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil) {
1389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1391 HDC hDc;
1392 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1393 HRESULT hr = WINED3D_OK;
1394 IUnknown *bufferParent;
1395 BOOL displaymode_set = FALSE;
1396 WINED3DDISPLAYMODE Mode;
1397 const StaticPixelFormatDesc *formatDesc;
1399 TRACE("(%p) : Created Additional Swap Chain\n", This);
1401 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1402 * does a device hold a reference to a swap chain giving them a lifetime of the device
1403 * or does the swap chain notify the device of its destruction.
1404 *******************************/
1406 /* Check the params */
1407 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1408 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1409 return WINED3DERR_INVALIDCALL;
1410 } else if (pPresentationParameters->BackBufferCount > 1) {
1411 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1414 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1416 /*********************
1417 * Lookup the window Handle and the relating X window handle
1418 ********************/
1420 /* Setup hwnd we are using, plus which display this equates to */
1421 object->win_handle = pPresentationParameters->hDeviceWindow;
1422 if (!object->win_handle) {
1423 object->win_handle = This->createParms.hFocusWindow;
1425 if(!This->ddraw_window) IWineD3DDevice_SetHWND(iface, object->win_handle);
1427 hDc = GetDC(object->win_handle);
1428 TRACE("Using hDc %p\n", hDc);
1430 if (NULL == hDc) {
1431 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1432 return WINED3DERR_NOTAVAILABLE;
1435 /* Get info on the current display setup */
1436 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1437 object->orig_width = Mode.Width;
1438 object->orig_height = Mode.Height;
1439 object->orig_fmt = Mode.Format;
1440 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1442 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1443 * then the corresponding dimension of the client area of the hDeviceWindow
1444 * (or the focus window, if hDeviceWindow is NULL) is taken.
1445 **********************/
1447 if (pPresentationParameters->Windowed &&
1448 ((pPresentationParameters->BackBufferWidth == 0) ||
1449 (pPresentationParameters->BackBufferHeight == 0) ||
1450 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1452 RECT Rect;
1453 GetClientRect(object->win_handle, &Rect);
1455 if (pPresentationParameters->BackBufferWidth == 0) {
1456 pPresentationParameters->BackBufferWidth = Rect.right;
1457 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1459 if (pPresentationParameters->BackBufferHeight == 0) {
1460 pPresentationParameters->BackBufferHeight = Rect.bottom;
1461 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1463 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1464 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1465 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1469 /* Put the correct figures in the presentation parameters */
1470 TRACE("Copying across presentation parameters\n");
1471 object->presentParms = *pPresentationParameters;
1473 TRACE("calling rendertarget CB\n");
1474 hr = D3DCB_CreateRenderTarget(This->parent,
1475 parent,
1476 object->presentParms.BackBufferWidth,
1477 object->presentParms.BackBufferHeight,
1478 object->presentParms.BackBufferFormat,
1479 object->presentParms.MultiSampleType,
1480 object->presentParms.MultiSampleQuality,
1481 TRUE /* Lockable */,
1482 &object->frontBuffer,
1483 NULL /* pShared (always null)*/);
1484 if (object->frontBuffer != NULL) {
1485 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1486 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1487 } else {
1488 ERR("Failed to create the front buffer\n");
1489 goto error;
1492 /*********************
1493 * Windowed / Fullscreen
1494 *******************/
1497 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1498 * so we should really check to see if there is a fullscreen swapchain already
1499 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1500 **************************************/
1502 if (!pPresentationParameters->Windowed) {
1503 WINED3DDISPLAYMODE mode;
1506 /* Change the display settings */
1507 mode.Width = pPresentationParameters->BackBufferWidth;
1508 mode.Height = pPresentationParameters->BackBufferHeight;
1509 mode.Format = pPresentationParameters->BackBufferFormat;
1510 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1512 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1513 displaymode_set = TRUE;
1514 IWineD3DDevice_SetFullscreen(iface, TRUE);
1518 * Create an opengl context for the display visual
1519 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1520 * use different properties after that point in time. FIXME: How to handle when requested format
1521 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1522 * it chooses is identical to the one already being used!
1523 **********************************/
1524 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1526 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1527 if(!object->context)
1528 return E_OUTOFMEMORY;
1529 object->num_contexts = 1;
1531 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1532 if (!object->context[0]) {
1533 ERR("Failed to create a new context\n");
1534 hr = WINED3DERR_NOTAVAILABLE;
1535 goto error;
1536 } else {
1537 TRACE("Context created (HWND=%p, glContext=%p)\n",
1538 object->win_handle, object->context[0]->glCtx);
1541 /*********************
1542 * Create the back, front and stencil buffers
1543 *******************/
1544 if(object->presentParms.BackBufferCount > 0) {
1545 int i;
1547 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1548 if(!object->backBuffer) {
1549 ERR("Out of memory\n");
1550 hr = E_OUTOFMEMORY;
1551 goto error;
1554 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1555 TRACE("calling rendertarget CB\n");
1556 hr = D3DCB_CreateRenderTarget(This->parent,
1557 parent,
1558 object->presentParms.BackBufferWidth,
1559 object->presentParms.BackBufferHeight,
1560 object->presentParms.BackBufferFormat,
1561 object->presentParms.MultiSampleType,
1562 object->presentParms.MultiSampleQuality,
1563 TRUE /* Lockable */,
1564 &object->backBuffer[i],
1565 NULL /* pShared (always null)*/);
1566 if(hr == WINED3D_OK && object->backBuffer[i]) {
1567 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1568 } else {
1569 ERR("Cannot create new back buffer\n");
1570 goto error;
1572 ENTER_GL();
1573 glDrawBuffer(GL_BACK);
1574 checkGLcall("glDrawBuffer(GL_BACK)");
1575 LEAVE_GL();
1577 } else {
1578 object->backBuffer = NULL;
1580 /* Single buffering - draw to front buffer */
1581 ENTER_GL();
1582 glDrawBuffer(GL_FRONT);
1583 checkGLcall("glDrawBuffer(GL_FRONT)");
1584 LEAVE_GL();
1587 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1588 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK) {
1589 TRACE("Creating depth stencil buffer\n");
1590 if (This->auto_depth_stencil_buffer == NULL ) {
1591 hr = D3DCB_CreateDepthStencil(This->parent,
1592 parent,
1593 object->presentParms.BackBufferWidth,
1594 object->presentParms.BackBufferHeight,
1595 object->presentParms.AutoDepthStencilFormat,
1596 object->presentParms.MultiSampleType,
1597 object->presentParms.MultiSampleQuality,
1598 FALSE /* FIXME: Discard */,
1599 &This->auto_depth_stencil_buffer,
1600 NULL /* pShared (always null)*/ );
1601 if (This->auto_depth_stencil_buffer != NULL)
1602 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1605 /** TODO: A check on width, height and multisample types
1606 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1607 ****************************/
1608 object->wantsDepthStencilBuffer = TRUE;
1609 } else {
1610 object->wantsDepthStencilBuffer = FALSE;
1613 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1615 TRACE("Created swapchain %p\n", object);
1616 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1617 return WINED3D_OK;
1619 error:
1620 if (displaymode_set) {
1621 DEVMODEW devmode;
1622 RECT clip_rc;
1624 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1625 ClipCursor(NULL);
1627 /* Change the display settings */
1628 memset(&devmode, 0, sizeof(devmode));
1629 devmode.dmSize = sizeof(devmode);
1630 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1631 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1632 devmode.dmPelsWidth = object->orig_width;
1633 devmode.dmPelsHeight = object->orig_height;
1634 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1637 if (object->backBuffer) {
1638 int i;
1639 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1640 if(object->backBuffer[i]) {
1641 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1642 IUnknown_Release(bufferParent); /* once for the get parent */
1643 if (IUnknown_Release(bufferParent) > 0) {
1644 FIXME("(%p) Something's still holding the back buffer\n",This);
1648 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1649 object->backBuffer = NULL;
1651 if(object->context[0])
1652 DestroyContext(This, object->context[0]);
1653 if(object->frontBuffer) {
1654 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1655 IUnknown_Release(bufferParent); /* once for the get parent */
1656 if (IUnknown_Release(bufferParent) > 0) {
1657 FIXME("(%p) Something's still holding the front buffer\n",This);
1660 HeapFree(GetProcessHeap(), 0, object);
1661 return hr;
1664 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1665 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1666 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1667 TRACE("(%p)\n", This);
1669 return This->NumberOfSwapChains;
1672 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1673 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1674 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1676 if(iSwapChain < This->NumberOfSwapChains) {
1677 *pSwapChain = This->swapchains[iSwapChain];
1678 IWineD3DSwapChain_AddRef(*pSwapChain);
1679 TRACE("(%p) returning %p\n", This, *pSwapChain);
1680 return WINED3D_OK;
1681 } else {
1682 TRACE("Swapchain out of range\n");
1683 *pSwapChain = NULL;
1684 return WINED3DERR_INVALIDCALL;
1688 /*****
1689 * Vertex Declaration
1690 *****/
1691 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1692 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1693 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1694 IWineD3DVertexDeclarationImpl *object = NULL;
1695 HRESULT hr = WINED3D_OK;
1697 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1698 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1700 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1702 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1703 if(FAILED(hr)) {
1704 *ppVertexDeclaration = NULL;
1705 HeapFree(GetProcessHeap(), 0, object);
1708 return hr;
1711 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1712 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1714 unsigned int idx, idx2;
1715 unsigned int offset;
1716 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1717 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1718 BOOL has_blend_idx = has_blend &&
1719 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1720 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1721 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1722 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1723 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1724 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1725 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1727 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1728 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1730 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1731 WINED3DVERTEXELEMENT *elements = NULL;
1733 unsigned int size;
1734 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1735 if (has_blend_idx) num_blends--;
1737 /* Compute declaration size */
1738 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1739 has_psize + has_diffuse + has_specular + num_textures + 1;
1741 /* convert the declaration */
1742 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1743 if (!elements)
1744 return 0;
1746 elements[size-1] = end_element;
1747 idx = 0;
1748 if (has_pos) {
1749 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1750 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1751 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1753 else {
1754 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1755 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1757 elements[idx].UsageIndex = 0;
1758 idx++;
1760 if (has_blend && (num_blends > 0)) {
1761 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1762 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1763 else
1764 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1765 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1766 elements[idx].UsageIndex = 0;
1767 idx++;
1769 if (has_blend_idx) {
1770 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1771 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1772 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1773 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1774 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1775 else
1776 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1777 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1778 elements[idx].UsageIndex = 0;
1779 idx++;
1781 if (has_normal) {
1782 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1783 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1784 elements[idx].UsageIndex = 0;
1785 idx++;
1787 if (has_psize) {
1788 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1789 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1790 elements[idx].UsageIndex = 0;
1791 idx++;
1793 if (has_diffuse) {
1794 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1795 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1796 elements[idx].UsageIndex = 0;
1797 idx++;
1799 if (has_specular) {
1800 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1801 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1802 elements[idx].UsageIndex = 1;
1803 idx++;
1805 for (idx2 = 0; idx2 < num_textures; idx2++) {
1806 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1807 switch (numcoords) {
1808 case WINED3DFVF_TEXTUREFORMAT1:
1809 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 break;
1811 case WINED3DFVF_TEXTUREFORMAT2:
1812 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1813 break;
1814 case WINED3DFVF_TEXTUREFORMAT3:
1815 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1816 break;
1817 case WINED3DFVF_TEXTUREFORMAT4:
1818 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1819 break;
1821 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1822 elements[idx].UsageIndex = idx2;
1823 idx++;
1826 /* Now compute offsets, and initialize the rest of the fields */
1827 for (idx = 0, offset = 0; idx < size-1; idx++) {
1828 elements[idx].Stream = 0;
1829 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1830 elements[idx].Offset = offset;
1831 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1834 *ppVertexElements = elements;
1835 return size;
1838 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1839 WINED3DVERTEXELEMENT* elements = NULL;
1840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1841 unsigned int size;
1842 DWORD hr;
1844 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1845 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1847 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1848 HeapFree(GetProcessHeap(), 0, elements);
1849 if (hr != S_OK) return hr;
1851 return WINED3D_OK;
1854 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1855 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1856 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1857 HRESULT hr = WINED3D_OK;
1858 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1859 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1861 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1863 if (vertex_declaration) {
1864 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1867 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1869 if (WINED3D_OK != hr) {
1870 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1871 IWineD3DVertexShader_Release(*ppVertexShader);
1872 return WINED3DERR_INVALIDCALL;
1874 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1876 return WINED3D_OK;
1879 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1880 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1881 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1882 HRESULT hr = WINED3D_OK;
1884 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1885 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1886 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1887 if (WINED3D_OK == hr) {
1888 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1889 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1890 } else {
1891 WARN("(%p) : Failed to create pixel shader\n", This);
1894 return hr;
1897 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1898 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1899 IWineD3DPaletteImpl *object;
1900 HRESULT hr;
1901 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1903 /* Create the new object */
1904 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1905 if(!object) {
1906 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1907 return E_OUTOFMEMORY;
1910 object->lpVtbl = &IWineD3DPalette_Vtbl;
1911 object->ref = 1;
1912 object->Flags = Flags;
1913 object->parent = Parent;
1914 object->wineD3DDevice = This;
1915 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1917 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1919 if(!object->hpal) {
1920 HeapFree( GetProcessHeap(), 0, object);
1921 return E_OUTOFMEMORY;
1924 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1925 if(FAILED(hr)) {
1926 IWineD3DPalette_Release((IWineD3DPalette *) object);
1927 return hr;
1930 *Palette = (IWineD3DPalette *) object;
1932 return WINED3D_OK;
1935 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1936 HBITMAP hbm;
1937 BITMAP bm;
1938 HRESULT hr;
1939 HDC dcb = NULL, dcs = NULL;
1940 WINEDDCOLORKEY colorkey;
1942 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1943 if(hbm)
1945 GetObjectA(hbm, sizeof(BITMAP), &bm);
1946 dcb = CreateCompatibleDC(NULL);
1947 if(!dcb) goto out;
1948 SelectObject(dcb, hbm);
1950 else
1952 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1953 * couldn't be loaded
1955 memset(&bm, 0, sizeof(bm));
1956 bm.bmWidth = 32;
1957 bm.bmHeight = 32;
1960 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1961 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1962 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1963 if(FAILED(hr)) {
1964 ERR("Wine logo requested, but failed to create surface\n");
1965 goto out;
1968 if(dcb) {
1969 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1970 if(FAILED(hr)) goto out;
1971 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1972 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1974 colorkey.dwColorSpaceLowValue = 0;
1975 colorkey.dwColorSpaceHighValue = 0;
1976 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1977 } else {
1978 /* Fill the surface with a white color to show that wined3d is there */
1979 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1982 out:
1983 if(dcb) {
1984 DeleteDC(dcb);
1986 if(hbm) {
1987 DeleteObject(hbm);
1989 return;
1992 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
1993 unsigned int i;
1994 /* Under DirectX you can have texture stage operations even if no texture is
1995 bound, whereas opengl will only do texture operations when a valid texture is
1996 bound. We emulate this by creating dummy textures and binding them to each
1997 texture stage, but disable all stages by default. Hence if a stage is enabled
1998 then the default texture will kick in until replaced by a SetTexture call */
1999 ENTER_GL();
2001 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2002 /* The dummy texture does not have client storage backing */
2003 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2004 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2006 for (i = 0; i < GL_LIMITS(textures); i++) {
2007 GLubyte white = 255;
2009 /* Make appropriate texture active */
2010 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2011 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2012 checkGLcall("glActiveTextureARB");
2013 } else if (i > 0) {
2014 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2017 /* Generate an opengl texture name */
2018 glGenTextures(1, &This->dummyTextureName[i]);
2019 checkGLcall("glGenTextures");
2020 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2022 /* Generate a dummy 2d texture (not using 1d because they cause many
2023 * DRI drivers fall back to sw) */
2024 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2025 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2026 checkGLcall("glBindTexture");
2028 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2029 checkGLcall("glTexImage2D");
2031 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2032 /* Reenable because if supported it is enabled by default */
2033 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2034 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2037 LEAVE_GL();
2040 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2041 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2042 IWineD3DSwapChainImpl *swapchain = NULL;
2043 HRESULT hr;
2044 DWORD state;
2045 unsigned int i;
2047 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2048 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2049 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2051 /* TODO: Test if OpenGL is compiled in and loaded */
2053 TRACE("(%p) : Creating stateblock\n", This);
2054 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2055 hr = IWineD3DDevice_CreateStateBlock(iface,
2056 WINED3DSBT_INIT,
2057 (IWineD3DStateBlock **)&This->stateBlock,
2058 NULL);
2059 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2060 WARN("Failed to create stateblock\n");
2061 goto err_out;
2063 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2064 This->updateStateBlock = This->stateBlock;
2065 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2067 hr = allocate_shader_constants(This->updateStateBlock);
2068 if (WINED3D_OK != hr) {
2069 goto err_out;
2072 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2073 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2074 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2076 This->NumberOfPalettes = 1;
2077 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2078 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2079 ERR("Out of memory!\n");
2080 goto err_out;
2082 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2083 if(!This->palettes[0]) {
2084 ERR("Out of memory!\n");
2085 goto err_out;
2087 for (i = 0; i < 256; ++i) {
2088 This->palettes[0][i].peRed = 0xFF;
2089 This->palettes[0][i].peGreen = 0xFF;
2090 This->palettes[0][i].peBlue = 0xFF;
2091 This->palettes[0][i].peFlags = 0xFF;
2093 This->currentPalette = 0;
2095 /* Initialize the texture unit mapping to a 1:1 mapping */
2096 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2097 if (state < GL_LIMITS(fragment_samplers)) {
2098 This->texUnitMap[state] = state;
2099 This->rev_tex_unit_map[state] = state;
2100 } else {
2101 This->texUnitMap[state] = -1;
2102 This->rev_tex_unit_map[state] = -1;
2106 /* Setup the implicit swapchain */
2107 TRACE("Creating implicit swapchain\n");
2108 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2109 if (FAILED(hr) || !swapchain) {
2110 WARN("Failed to create implicit swapchain\n");
2111 goto err_out;
2114 This->NumberOfSwapChains = 1;
2115 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2116 if(!This->swapchains) {
2117 ERR("Out of memory!\n");
2118 goto err_out;
2120 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2122 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2123 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2124 This->render_targets[0] = swapchain->backBuffer[0];
2125 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2127 else {
2128 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2129 This->render_targets[0] = swapchain->frontBuffer;
2130 This->lastActiveRenderTarget = swapchain->frontBuffer;
2132 IWineD3DSurface_AddRef(This->render_targets[0]);
2133 This->activeContext = swapchain->context[0];
2134 This->lastThread = GetCurrentThreadId();
2136 /* Depth Stencil support */
2137 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2138 if (NULL != This->stencilBufferTarget) {
2139 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2142 hr = This->shader_backend->shader_alloc_private(iface);
2143 if(FAILED(hr)) {
2144 TRACE("Shader private data couldn't be allocated\n");
2145 goto err_out;
2147 hr = This->frag_pipe->alloc_private(iface);
2148 if(FAILED(hr)) {
2149 TRACE("Fragment pipeline private data couldn't be allocated\n");
2150 goto err_out;
2153 /* Set up some starting GL setup */
2155 /* Setup all the devices defaults */
2156 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2157 create_dummy_textures(This);
2159 ENTER_GL();
2161 #if 0
2162 IWineD3DImpl_CheckGraphicsMemory();
2163 #endif
2165 { /* Set a default viewport */
2166 WINED3DVIEWPORT vp;
2167 vp.X = 0;
2168 vp.Y = 0;
2169 vp.Width = pPresentationParameters->BackBufferWidth;
2170 vp.Height = pPresentationParameters->BackBufferHeight;
2171 vp.MinZ = 0.0f;
2172 vp.MaxZ = 1.0f;
2173 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2176 /* Initialize the current view state */
2177 This->view_ident = 1;
2178 This->contexts[0]->last_was_rhw = 0;
2179 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2180 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2182 switch(wined3d_settings.offscreen_rendering_mode) {
2183 case ORM_FBO:
2184 case ORM_PBUFFER:
2185 This->offscreenBuffer = GL_BACK;
2186 break;
2188 case ORM_BACKBUFFER:
2190 if(This->activeContext->aux_buffers > 0) {
2191 TRACE("Using auxilliary buffer for offscreen rendering\n");
2192 This->offscreenBuffer = GL_AUX0;
2193 } else {
2194 TRACE("Using back buffer for offscreen rendering\n");
2195 This->offscreenBuffer = GL_BACK;
2200 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2201 LEAVE_GL();
2203 /* Clear the screen */
2204 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2205 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2206 0x00, 1.0, 0);
2208 This->d3d_initialized = TRUE;
2210 if(wined3d_settings.logo) {
2211 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2213 This->highest_dirty_ps_const = 0;
2214 This->highest_dirty_vs_const = 0;
2215 return WINED3D_OK;
2217 err_out:
2218 HeapFree(GetProcessHeap(), 0, This->render_targets);
2219 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2220 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2221 HeapFree(GetProcessHeap(), 0, This->swapchains);
2222 This->NumberOfSwapChains = 0;
2223 if(This->palettes) {
2224 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2225 HeapFree(GetProcessHeap(), 0, This->palettes);
2227 This->NumberOfPalettes = 0;
2228 if(swapchain) {
2229 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2231 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2232 if(This->stateBlock) {
2233 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2234 This->stateBlock = NULL;
2236 This->shader_backend->shader_free_private(iface);
2237 This->frag_pipe->free_private(iface);
2238 return hr;
2241 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2243 int sampler;
2244 UINT i;
2245 TRACE("(%p)\n", This);
2247 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2249 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2250 * it was created. Thus make sure a context is active for the glDelete* calls
2252 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2254 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2256 TRACE("Deleting high order patches\n");
2257 for(i = 0; i < PATCHMAP_SIZE; i++) {
2258 struct list *e1, *e2;
2259 struct WineD3DRectPatch *patch;
2260 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2261 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2262 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2266 /* Delete the palette conversion shader if it is around */
2267 if(This->paletteConversionShader) {
2268 ENTER_GL();
2269 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2270 LEAVE_GL();
2271 This->paletteConversionShader = 0;
2274 /* Delete the pbuffer context if there is any */
2275 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2277 /* Delete the mouse cursor texture */
2278 if(This->cursorTexture) {
2279 ENTER_GL();
2280 glDeleteTextures(1, &This->cursorTexture);
2281 LEAVE_GL();
2282 This->cursorTexture = 0;
2285 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2286 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2288 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2289 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2292 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2293 * private data, it might contain opengl pointers
2295 if(This->depth_blt_texture) {
2296 glDeleteTextures(1, &This->depth_blt_texture);
2297 This->depth_blt_texture = 0;
2299 if (This->depth_blt_rb) {
2300 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2301 This->depth_blt_rb = 0;
2302 This->depth_blt_rb_w = 0;
2303 This->depth_blt_rb_h = 0;
2306 /* Release the update stateblock */
2307 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2308 if(This->updateStateBlock != This->stateBlock)
2309 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2311 This->updateStateBlock = NULL;
2313 { /* because were not doing proper internal refcounts releasing the primary state block
2314 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2315 to set this->stateBlock = NULL; first */
2316 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2317 This->stateBlock = NULL;
2319 /* Release the stateblock */
2320 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2321 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2325 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2326 This->shader_backend->shader_free_private(iface);
2327 This->frag_pipe->free_private(iface);
2329 /* Release the buffers (with sanity checks)*/
2330 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2331 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2332 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2333 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2335 This->stencilBufferTarget = NULL;
2337 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2338 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2339 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2341 TRACE("Setting rendertarget to NULL\n");
2342 This->render_targets[0] = NULL;
2344 if (This->auto_depth_stencil_buffer) {
2345 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2346 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2348 This->auto_depth_stencil_buffer = NULL;
2351 for(i=0; i < This->NumberOfSwapChains; i++) {
2352 TRACE("Releasing the implicit swapchain %d\n", i);
2353 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2354 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2358 HeapFree(GetProcessHeap(), 0, This->swapchains);
2359 This->swapchains = NULL;
2360 This->NumberOfSwapChains = 0;
2362 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2363 HeapFree(GetProcessHeap(), 0, This->palettes);
2364 This->palettes = NULL;
2365 This->NumberOfPalettes = 0;
2367 HeapFree(GetProcessHeap(), 0, This->render_targets);
2368 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2369 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2370 This->render_targets = NULL;
2371 This->fbo_color_attachments = NULL;
2372 This->draw_buffers = NULL;
2374 This->d3d_initialized = FALSE;
2375 return WINED3D_OK;
2378 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2379 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2380 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2382 /* Setup the window for fullscreen mode */
2383 if(fullscreen && !This->ddraw_fullscreen) {
2384 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2385 } else if(!fullscreen && This->ddraw_fullscreen) {
2386 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2389 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2390 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2391 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2392 * separately.
2394 This->ddraw_fullscreen = fullscreen;
2397 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2398 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2399 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2401 * There is no way to deactivate thread safety once it is enabled.
2403 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2406 /*For now just store the flag(needed in case of ddraw) */
2407 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2409 return;
2412 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2413 DEVMODEW devmode;
2414 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2415 LONG ret;
2416 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2417 RECT clip_rc;
2419 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2421 /* Resize the screen even without a window:
2422 * The app could have unset it with SetCooperativeLevel, but not called
2423 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2424 * but we don't have any hwnd
2427 memset(&devmode, 0, sizeof(devmode));
2428 devmode.dmSize = sizeof(devmode);
2429 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2430 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2431 devmode.dmPelsWidth = pMode->Width;
2432 devmode.dmPelsHeight = pMode->Height;
2434 devmode.dmDisplayFrequency = pMode->RefreshRate;
2435 if (pMode->RefreshRate != 0) {
2436 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2439 /* Only change the mode if necessary */
2440 if( (This->ddraw_width == pMode->Width) &&
2441 (This->ddraw_height == pMode->Height) &&
2442 (This->ddraw_format == pMode->Format) &&
2443 (pMode->RefreshRate == 0) ) {
2444 return WINED3D_OK;
2447 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2448 if (ret != DISP_CHANGE_SUCCESSFUL) {
2449 if(devmode.dmDisplayFrequency != 0) {
2450 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2451 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2452 devmode.dmDisplayFrequency = 0;
2453 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2455 if(ret != DISP_CHANGE_SUCCESSFUL) {
2456 return WINED3DERR_NOTAVAILABLE;
2460 /* Store the new values */
2461 This->ddraw_width = pMode->Width;
2462 This->ddraw_height = pMode->Height;
2463 This->ddraw_format = pMode->Format;
2465 /* Only do this with a window of course, and only if we're fullscreened */
2466 if(This->ddraw_window && This->ddraw_fullscreen)
2467 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2469 /* And finally clip mouse to our screen */
2470 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2471 ClipCursor(&clip_rc);
2473 return WINED3D_OK;
2476 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2477 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2478 *ppD3D= This->wineD3D;
2479 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2480 IWineD3D_AddRef(*ppD3D);
2481 return WINED3D_OK;
2484 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2485 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2487 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2488 (This->adapter->TextureRam/(1024*1024)),
2489 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2490 /* return simulated texture memory left */
2491 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2496 /*****
2497 * Get / Set FVF
2498 *****/
2499 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2500 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2502 /* Update the current state block */
2503 This->updateStateBlock->changed.fvf = TRUE;
2505 if(This->updateStateBlock->fvf == fvf) {
2506 TRACE("Application is setting the old fvf over, nothing to do\n");
2507 return WINED3D_OK;
2510 This->updateStateBlock->fvf = fvf;
2511 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2512 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2513 return WINED3D_OK;
2517 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2519 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2520 *pfvf = This->stateBlock->fvf;
2521 return WINED3D_OK;
2524 /*****
2525 * Get / Set Stream Source
2526 *****/
2527 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2528 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 IWineD3DVertexBuffer *oldSrc;
2531 if (StreamNumber >= MAX_STREAMS) {
2532 WARN("Stream out of range %d\n", StreamNumber);
2533 return WINED3DERR_INVALIDCALL;
2534 } else if(OffsetInBytes & 0x3) {
2535 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2536 return WINED3DERR_INVALIDCALL;
2539 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2540 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2542 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2544 if(oldSrc == pStreamData &&
2545 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2546 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2547 TRACE("Application is setting the old values over, nothing to do\n");
2548 return WINED3D_OK;
2551 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2552 if (pStreamData) {
2553 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2554 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2557 /* Handle recording of state blocks */
2558 if (This->isRecordingState) {
2559 TRACE("Recording... not performing anything\n");
2560 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2561 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2562 return WINED3D_OK;
2565 /* Need to do a getParent and pass the references up */
2566 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2567 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2568 so for now, just count internally */
2569 if (pStreamData != NULL) {
2570 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2571 InterlockedIncrement(&vbImpl->bindCount);
2572 IWineD3DVertexBuffer_AddRef(pStreamData);
2574 if (oldSrc != NULL) {
2575 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2576 IWineD3DVertexBuffer_Release(oldSrc);
2579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2581 return WINED3D_OK;
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2587 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2588 This->stateBlock->streamSource[StreamNumber],
2589 This->stateBlock->streamOffset[StreamNumber],
2590 This->stateBlock->streamStride[StreamNumber]);
2592 if (StreamNumber >= MAX_STREAMS) {
2593 WARN("Stream out of range %d\n", StreamNumber);
2594 return WINED3DERR_INVALIDCALL;
2596 *pStream = This->stateBlock->streamSource[StreamNumber];
2597 *pStride = This->stateBlock->streamStride[StreamNumber];
2598 if (pOffset) {
2599 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2602 if (*pStream != NULL) {
2603 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2605 return WINED3D_OK;
2608 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2609 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2610 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2611 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2613 /* Verify input at least in d3d9 this is invalid*/
2614 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2615 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2616 return WINED3DERR_INVALIDCALL;
2618 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2619 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2620 return WINED3DERR_INVALIDCALL;
2622 if( Divider == 0 ){
2623 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2624 return WINED3DERR_INVALIDCALL;
2627 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2628 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2630 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2631 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2633 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2634 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2635 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2638 return WINED3D_OK;
2641 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2644 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2645 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2647 TRACE("(%p) : returning %d\n", This, *Divider);
2649 return WINED3D_OK;
2652 /*****
2653 * Get / Set & Multiply Transform
2654 *****/
2655 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2658 /* Most of this routine, comments included copied from ddraw tree initially: */
2659 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2661 /* Handle recording of state blocks */
2662 if (This->isRecordingState) {
2663 TRACE("Recording... not performing anything\n");
2664 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2665 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2666 return WINED3D_OK;
2670 * If the new matrix is the same as the current one,
2671 * we cut off any further processing. this seems to be a reasonable
2672 * optimization because as was noticed, some apps (warcraft3 for example)
2673 * tend towards setting the same matrix repeatedly for some reason.
2675 * From here on we assume that the new matrix is different, wherever it matters.
2677 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2678 TRACE("The app is setting the same matrix over again\n");
2679 return WINED3D_OK;
2680 } else {
2681 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2685 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2686 where ViewMat = Camera space, WorldMat = world space.
2688 In OpenGL, camera and world space is combined into GL_MODELVIEW
2689 matrix. The Projection matrix stay projection matrix.
2692 /* Capture the times we can just ignore the change for now */
2693 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2694 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2695 /* Handled by the state manager */
2698 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2699 return WINED3D_OK;
2702 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2703 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2704 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2705 *pMatrix = This->stateBlock->transforms[State];
2706 return WINED3D_OK;
2709 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2710 WINED3DMATRIX *mat = NULL;
2711 WINED3DMATRIX temp;
2713 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2714 * below means it will be recorded in a state block change, but it
2715 * works regardless where it is recorded.
2716 * If this is found to be wrong, change to StateBlock.
2718 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2719 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2721 if (State < HIGHEST_TRANSFORMSTATE)
2723 mat = &This->updateStateBlock->transforms[State];
2724 } else {
2725 FIXME("Unhandled transform state!!\n");
2728 multiply_matrix(&temp, mat, pMatrix);
2730 /* Apply change via set transform - will reapply to eg. lights this way */
2731 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2734 /*****
2735 * Get / Set Light
2736 *****/
2737 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2738 you can reference any indexes you want as long as that number max are enabled at any
2739 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2740 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2741 but when recording, just build a chain pretty much of commands to be replayed. */
2743 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2744 float rho;
2745 PLIGHTINFOEL *object = NULL;
2746 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2747 struct list *e;
2749 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2750 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2752 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2753 * the gl driver.
2755 if(!pLight) {
2756 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2757 return WINED3DERR_INVALIDCALL;
2760 switch(pLight->Type) {
2761 case WINED3DLIGHT_POINT:
2762 case WINED3DLIGHT_SPOT:
2763 case WINED3DLIGHT_PARALLELPOINT:
2764 case WINED3DLIGHT_GLSPOT:
2765 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2766 * most wanted
2768 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2769 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2770 return WINED3DERR_INVALIDCALL;
2772 break;
2774 case WINED3DLIGHT_DIRECTIONAL:
2775 /* Ignores attenuation */
2776 break;
2778 default:
2779 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2780 return WINED3DERR_INVALIDCALL;
2783 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2784 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2785 if(object->OriginalIndex == Index) break;
2786 object = NULL;
2789 if(!object) {
2790 TRACE("Adding new light\n");
2791 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2792 if(!object) {
2793 ERR("Out of memory error when allocating a light\n");
2794 return E_OUTOFMEMORY;
2796 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2797 object->glIndex = -1;
2798 object->OriginalIndex = Index;
2799 object->changed = TRUE;
2802 /* Initialize the object */
2803 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,
2804 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2805 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2806 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2807 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2808 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2809 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2811 /* Save away the information */
2812 object->OriginalParms = *pLight;
2814 switch (pLight->Type) {
2815 case WINED3DLIGHT_POINT:
2816 /* Position */
2817 object->lightPosn[0] = pLight->Position.x;
2818 object->lightPosn[1] = pLight->Position.y;
2819 object->lightPosn[2] = pLight->Position.z;
2820 object->lightPosn[3] = 1.0f;
2821 object->cutoff = 180.0f;
2822 /* FIXME: Range */
2823 break;
2825 case WINED3DLIGHT_DIRECTIONAL:
2826 /* Direction */
2827 object->lightPosn[0] = -pLight->Direction.x;
2828 object->lightPosn[1] = -pLight->Direction.y;
2829 object->lightPosn[2] = -pLight->Direction.z;
2830 object->lightPosn[3] = 0.0;
2831 object->exponent = 0.0f;
2832 object->cutoff = 180.0f;
2833 break;
2835 case WINED3DLIGHT_SPOT:
2836 /* Position */
2837 object->lightPosn[0] = pLight->Position.x;
2838 object->lightPosn[1] = pLight->Position.y;
2839 object->lightPosn[2] = pLight->Position.z;
2840 object->lightPosn[3] = 1.0;
2842 /* Direction */
2843 object->lightDirn[0] = pLight->Direction.x;
2844 object->lightDirn[1] = pLight->Direction.y;
2845 object->lightDirn[2] = pLight->Direction.z;
2846 object->lightDirn[3] = 1.0;
2849 * opengl-ish and d3d-ish spot lights use too different models for the
2850 * light "intensity" as a function of the angle towards the main light direction,
2851 * so we only can approximate very roughly.
2852 * however spot lights are rather rarely used in games (if ever used at all).
2853 * furthermore if still used, probably nobody pays attention to such details.
2855 if (pLight->Falloff == 0) {
2856 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2857 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2858 * will always be 1.0 for both of them, and we don't have to care for the
2859 * rest of the rather complex calculation
2861 object->exponent = 0;
2862 } else {
2863 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2864 if (rho < 0.0001) rho = 0.0001f;
2865 object->exponent = -0.3/log(cos(rho/2));
2867 if (object->exponent > 128.0) {
2868 object->exponent = 128.0;
2870 object->cutoff = pLight->Phi*90/M_PI;
2872 /* FIXME: Range */
2873 break;
2875 default:
2876 FIXME("Unrecognized light type %d\n", pLight->Type);
2879 /* Update the live definitions if the light is currently assigned a glIndex */
2880 if (object->glIndex != -1 && !This->isRecordingState) {
2881 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2883 return WINED3D_OK;
2886 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2887 PLIGHTINFOEL *lightInfo = NULL;
2888 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2889 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2890 struct list *e;
2891 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2893 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2894 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2895 if(lightInfo->OriginalIndex == Index) break;
2896 lightInfo = NULL;
2899 if (lightInfo == NULL) {
2900 TRACE("Light information requested but light not defined\n");
2901 return WINED3DERR_INVALIDCALL;
2904 *pLight = lightInfo->OriginalParms;
2905 return WINED3D_OK;
2908 /*****
2909 * Get / Set Light Enable
2910 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2911 *****/
2912 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2913 PLIGHTINFOEL *lightInfo = NULL;
2914 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2915 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2916 struct list *e;
2917 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2919 /* Tests show true = 128...not clear why */
2920 Enable = Enable? 128: 0;
2922 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2923 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2924 if(lightInfo->OriginalIndex == Index) break;
2925 lightInfo = NULL;
2927 TRACE("Found light: %p\n", lightInfo);
2929 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2930 if (lightInfo == NULL) {
2932 TRACE("Light enabled requested but light not defined, so defining one!\n");
2933 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2935 /* Search for it again! Should be fairly quick as near head of list */
2936 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2937 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2938 if(lightInfo->OriginalIndex == Index) break;
2939 lightInfo = NULL;
2941 if (lightInfo == NULL) {
2942 FIXME("Adding default lights has failed dismally\n");
2943 return WINED3DERR_INVALIDCALL;
2947 lightInfo->enabledChanged = TRUE;
2948 if(!Enable) {
2949 if(lightInfo->glIndex != -1) {
2950 if(!This->isRecordingState) {
2951 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2954 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2955 lightInfo->glIndex = -1;
2956 } else {
2957 TRACE("Light already disabled, nothing to do\n");
2959 lightInfo->enabled = FALSE;
2960 } else {
2961 lightInfo->enabled = TRUE;
2962 if (lightInfo->glIndex != -1) {
2963 /* nop */
2964 TRACE("Nothing to do as light was enabled\n");
2965 } else {
2966 int i;
2967 /* Find a free gl light */
2968 for(i = 0; i < This->maxConcurrentLights; i++) {
2969 if(This->stateBlock->activeLights[i] == NULL) {
2970 This->stateBlock->activeLights[i] = lightInfo;
2971 lightInfo->glIndex = i;
2972 break;
2975 if(lightInfo->glIndex == -1) {
2976 /* Our tests show that Windows returns D3D_OK in this situation, even with
2977 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
2978 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
2979 * as well for those lights.
2981 * TODO: Test how this affects rendering
2983 FIXME("Too many concurrently active lights\n");
2984 return WINED3D_OK;
2987 /* i == lightInfo->glIndex */
2988 if(!This->isRecordingState) {
2989 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
2994 return WINED3D_OK;
2997 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
2999 PLIGHTINFOEL *lightInfo = NULL;
3000 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3001 struct list *e;
3002 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3003 TRACE("(%p) : for idx(%d)\n", This, Index);
3005 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3006 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3007 if(lightInfo->OriginalIndex == Index) break;
3008 lightInfo = NULL;
3011 if (lightInfo == NULL) {
3012 TRACE("Light enabled state requested but light not defined\n");
3013 return WINED3DERR_INVALIDCALL;
3015 /* true is 128 according to SetLightEnable */
3016 *pEnable = lightInfo->enabled ? 128 : 0;
3017 return WINED3D_OK;
3020 /*****
3021 * Get / Set Clip Planes
3022 *****/
3023 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3024 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3025 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3027 /* Validate Index */
3028 if (Index >= GL_LIMITS(clipplanes)) {
3029 TRACE("Application has requested clipplane this device doesn't support\n");
3030 return WINED3DERR_INVALIDCALL;
3033 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3035 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3036 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3037 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3038 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3039 TRACE("Application is setting old values over, nothing to do\n");
3040 return WINED3D_OK;
3043 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3044 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3045 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3046 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3048 /* Handle recording of state blocks */
3049 if (This->isRecordingState) {
3050 TRACE("Recording... not performing anything\n");
3051 return WINED3D_OK;
3054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3056 return WINED3D_OK;
3059 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3060 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3061 TRACE("(%p) : for idx %d\n", This, Index);
3063 /* Validate Index */
3064 if (Index >= GL_LIMITS(clipplanes)) {
3065 TRACE("Application has requested clipplane this device doesn't support\n");
3066 return WINED3DERR_INVALIDCALL;
3069 pPlane[0] = This->stateBlock->clipplane[Index][0];
3070 pPlane[1] = This->stateBlock->clipplane[Index][1];
3071 pPlane[2] = This->stateBlock->clipplane[Index][2];
3072 pPlane[3] = This->stateBlock->clipplane[Index][3];
3073 return WINED3D_OK;
3076 /*****
3077 * Get / Set Clip Plane Status
3078 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3079 *****/
3080 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3081 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3082 FIXME("(%p) : stub\n", This);
3083 if (NULL == pClipStatus) {
3084 return WINED3DERR_INVALIDCALL;
3086 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3087 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3088 return WINED3D_OK;
3091 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3092 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3093 FIXME("(%p) : stub\n", This);
3094 if (NULL == pClipStatus) {
3095 return WINED3DERR_INVALIDCALL;
3097 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3098 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3099 return WINED3D_OK;
3102 /*****
3103 * Get / Set Material
3104 *****/
3105 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3108 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3110 This->updateStateBlock->changed.material = TRUE;
3111 This->updateStateBlock->material = *pMaterial;
3113 /* Handle recording of state blocks */
3114 if (This->isRecordingState) {
3115 TRACE("Recording... not performing anything\n");
3116 return WINED3D_OK;
3119 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3120 return WINED3D_OK;
3123 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3124 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3125 *pMaterial = This->updateStateBlock->material;
3126 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3127 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3128 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3129 pMaterial->Ambient.b, pMaterial->Ambient.a);
3130 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3131 pMaterial->Specular.b, pMaterial->Specular.a);
3132 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3133 pMaterial->Emissive.b, pMaterial->Emissive.a);
3134 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3136 return WINED3D_OK;
3139 /*****
3140 * Get / Set Indices
3141 *****/
3142 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3143 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3144 IWineD3DIndexBuffer *oldIdxs;
3146 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3147 oldIdxs = This->updateStateBlock->pIndexData;
3149 This->updateStateBlock->changed.indices = TRUE;
3150 This->updateStateBlock->pIndexData = pIndexData;
3152 /* Handle recording of state blocks */
3153 if (This->isRecordingState) {
3154 TRACE("Recording... not performing anything\n");
3155 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3156 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3157 return WINED3D_OK;
3160 if(oldIdxs != pIndexData) {
3161 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3162 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3163 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3165 return WINED3D_OK;
3168 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3169 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3171 *ppIndexData = This->stateBlock->pIndexData;
3173 /* up ref count on ppindexdata */
3174 if (*ppIndexData) {
3175 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3176 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3177 }else{
3178 TRACE("(%p) No index data set\n", This);
3180 TRACE("Returning %p\n", *ppIndexData);
3182 return WINED3D_OK;
3185 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3186 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3188 TRACE("(%p)->(%d)\n", This, BaseIndex);
3190 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3191 TRACE("Application is setting the old value over, nothing to do\n");
3192 return WINED3D_OK;
3195 This->updateStateBlock->baseVertexIndex = BaseIndex;
3197 if (This->isRecordingState) {
3198 TRACE("Recording... not performing anything\n");
3199 return WINED3D_OK;
3201 /* The base vertex index affects the stream sources */
3202 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3203 return WINED3D_OK;
3206 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3208 TRACE("(%p) : base_index %p\n", This, base_index);
3210 *base_index = This->stateBlock->baseVertexIndex;
3212 TRACE("Returning %u\n", *base_index);
3214 return WINED3D_OK;
3217 /*****
3218 * Get / Set Viewports
3219 *****/
3220 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3221 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3223 TRACE("(%p)\n", This);
3224 This->updateStateBlock->changed.viewport = TRUE;
3225 This->updateStateBlock->viewport = *pViewport;
3227 /* Handle recording of state blocks */
3228 if (This->isRecordingState) {
3229 TRACE("Recording... not performing anything\n");
3230 return WINED3D_OK;
3233 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3234 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3236 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3237 return WINED3D_OK;
3241 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3242 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3243 TRACE("(%p)\n", This);
3244 *pViewport = This->stateBlock->viewport;
3245 return WINED3D_OK;
3248 /*****
3249 * Get / Set Render States
3250 * TODO: Verify against dx9 definitions
3251 *****/
3252 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 DWORD oldValue = This->stateBlock->renderState[State];
3257 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3259 This->updateStateBlock->changed.renderState[State] = TRUE;
3260 This->updateStateBlock->renderState[State] = Value;
3262 /* Handle recording of state blocks */
3263 if (This->isRecordingState) {
3264 TRACE("Recording... not performing anything\n");
3265 return WINED3D_OK;
3268 /* Compared here and not before the assignment to allow proper stateblock recording */
3269 if(Value == oldValue) {
3270 TRACE("Application is setting the old value over, nothing to do\n");
3271 } else {
3272 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3275 return WINED3D_OK;
3278 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3279 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3280 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3281 *pValue = This->stateBlock->renderState[State];
3282 return WINED3D_OK;
3285 /*****
3286 * Get / Set Sampler States
3287 * TODO: Verify against dx9 definitions
3288 *****/
3290 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 DWORD oldValue;
3294 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3295 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3297 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3298 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3301 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3302 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3303 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3306 * SetSampler is designed to allow for more than the standard up to 8 textures
3307 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3308 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3310 * http://developer.nvidia.com/object/General_FAQ.html#t6
3312 * There are two new settings for GForce
3313 * the sampler one:
3314 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3315 * and the texture one:
3316 * GL_MAX_TEXTURE_COORDS_ARB.
3317 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3318 ******************/
3320 oldValue = This->stateBlock->samplerState[Sampler][Type];
3321 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3322 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3324 /* Handle recording of state blocks */
3325 if (This->isRecordingState) {
3326 TRACE("Recording... not performing anything\n");
3327 return WINED3D_OK;
3330 if(oldValue == Value) {
3331 TRACE("Application is setting the old value over, nothing to do\n");
3332 return WINED3D_OK;
3335 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3337 return WINED3D_OK;
3340 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3341 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3343 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3344 This, Sampler, debug_d3dsamplerstate(Type), Type);
3346 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3347 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3350 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3351 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3352 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3354 *Value = This->stateBlock->samplerState[Sampler][Type];
3355 TRACE("(%p) : Returning %#x\n", This, *Value);
3357 return WINED3D_OK;
3360 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3361 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3363 This->updateStateBlock->changed.scissorRect = TRUE;
3364 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3365 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3366 return WINED3D_OK;
3368 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3370 if(This->isRecordingState) {
3371 TRACE("Recording... not performing anything\n");
3372 return WINED3D_OK;
3375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3377 return WINED3D_OK;
3380 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3383 *pRect = This->updateStateBlock->scissorRect;
3384 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3385 return WINED3D_OK;
3388 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3389 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3390 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3392 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3394 This->updateStateBlock->vertexDecl = pDecl;
3395 This->updateStateBlock->changed.vertexDecl = TRUE;
3397 if (This->isRecordingState) {
3398 TRACE("Recording... not performing anything\n");
3399 return WINED3D_OK;
3400 } else if(pDecl == oldDecl) {
3401 /* Checked after the assignment to allow proper stateblock recording */
3402 TRACE("Application is setting the old declaration over, nothing to do\n");
3403 return WINED3D_OK;
3406 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3407 return WINED3D_OK;
3410 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3411 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3413 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3415 *ppDecl = This->stateBlock->vertexDecl;
3416 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3417 return WINED3D_OK;
3420 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3422 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3424 This->updateStateBlock->vertexShader = pShader;
3425 This->updateStateBlock->changed.vertexShader = TRUE;
3427 if (This->isRecordingState) {
3428 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3429 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3430 TRACE("Recording... not performing anything\n");
3431 return WINED3D_OK;
3432 } else if(oldShader == pShader) {
3433 /* Checked here to allow proper stateblock recording */
3434 TRACE("App is setting the old shader over, nothing to do\n");
3435 return WINED3D_OK;
3438 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3439 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3440 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3444 return WINED3D_OK;
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 if (NULL == ppShader) {
3451 return WINED3DERR_INVALIDCALL;
3453 *ppShader = This->stateBlock->vertexShader;
3454 if( NULL != *ppShader)
3455 IWineD3DVertexShader_AddRef(*ppShader);
3457 TRACE("(%p) : returning %p\n", This, *ppShader);
3458 return WINED3D_OK;
3461 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3462 IWineD3DDevice *iface,
3463 UINT start,
3464 CONST BOOL *srcData,
3465 UINT count) {
3467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3468 int i, cnt = min(count, MAX_CONST_B - start);
3470 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3471 iface, srcData, start, count);
3473 if (srcData == NULL || cnt < 0)
3474 return WINED3DERR_INVALIDCALL;
3476 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3477 for (i = 0; i < cnt; i++)
3478 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3480 for (i = start; i < cnt + start; ++i) {
3481 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3484 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3486 return WINED3D_OK;
3489 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3490 IWineD3DDevice *iface,
3491 UINT start,
3492 BOOL *dstData,
3493 UINT count) {
3495 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3496 int cnt = min(count, MAX_CONST_B - start);
3498 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3499 iface, dstData, start, count);
3501 if (dstData == NULL || cnt < 0)
3502 return WINED3DERR_INVALIDCALL;
3504 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3505 return WINED3D_OK;
3508 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3509 IWineD3DDevice *iface,
3510 UINT start,
3511 CONST int *srcData,
3512 UINT count) {
3514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3515 int i, cnt = min(count, MAX_CONST_I - start);
3517 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3518 iface, srcData, start, count);
3520 if (srcData == NULL || cnt < 0)
3521 return WINED3DERR_INVALIDCALL;
3523 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3524 for (i = 0; i < cnt; i++)
3525 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3526 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3528 for (i = start; i < cnt + start; ++i) {
3529 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3532 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3534 return WINED3D_OK;
3537 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3538 IWineD3DDevice *iface,
3539 UINT start,
3540 int *dstData,
3541 UINT count) {
3543 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3544 int cnt = min(count, MAX_CONST_I - start);
3546 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3547 iface, dstData, start, count);
3549 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3550 return WINED3DERR_INVALIDCALL;
3552 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3553 return WINED3D_OK;
3556 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3557 IWineD3DDevice *iface,
3558 UINT start,
3559 CONST float *srcData,
3560 UINT count) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 int i;
3565 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3566 iface, srcData, start, count);
3568 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3569 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3570 return WINED3DERR_INVALIDCALL;
3572 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3573 if(TRACE_ON(d3d)) {
3574 for (i = 0; i < count; i++)
3575 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3576 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3579 for (i = start; i < count + start; ++i) {
3580 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3581 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3582 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3583 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3584 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3586 ptr->idx[ptr->count++] = i;
3587 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3591 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3593 return WINED3D_OK;
3596 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3597 IWineD3DDevice *iface,
3598 UINT start,
3599 CONST float *srcData,
3600 UINT count) {
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 int i;
3605 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3606 iface, srcData, start, count);
3608 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3609 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3610 return WINED3DERR_INVALIDCALL;
3612 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3613 if(TRACE_ON(d3d)) {
3614 for (i = 0; i < count; i++)
3615 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3616 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3619 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3620 * context. On a context switch the old context will be fully dirtified
3622 memset(This->activeContext->vshader_const_dirty + start, 1,
3623 sizeof(*This->activeContext->vshader_const_dirty) * count);
3624 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3626 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3628 return WINED3D_OK;
3631 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3632 IWineD3DDevice *iface,
3633 UINT start,
3634 float *dstData,
3635 UINT count) {
3637 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3638 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3640 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3641 iface, dstData, start, count);
3643 if (dstData == NULL || cnt < 0)
3644 return WINED3DERR_INVALIDCALL;
3646 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3647 return WINED3D_OK;
3650 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3651 DWORD i;
3652 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3653 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3657 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3658 int i = This->rev_tex_unit_map[unit];
3659 int j = This->texUnitMap[stage];
3661 This->texUnitMap[stage] = unit;
3662 if (i != -1 && i != stage) {
3663 This->texUnitMap[i] = -1;
3666 This->rev_tex_unit_map[unit] = stage;
3667 if (j != -1 && j != unit) {
3668 This->rev_tex_unit_map[j] = -1;
3672 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3673 int i;
3675 for (i = 0; i < MAX_TEXTURES; ++i) {
3676 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3677 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3678 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3679 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3680 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3681 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3682 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3683 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3685 if (color_op == WINED3DTOP_DISABLE) {
3686 /* Not used, and disable higher stages */
3687 while (i < MAX_TEXTURES) {
3688 This->fixed_function_usage_map[i] = FALSE;
3689 ++i;
3691 break;
3694 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3695 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3696 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3697 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3698 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3699 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3700 This->fixed_function_usage_map[i] = TRUE;
3701 } else {
3702 This->fixed_function_usage_map[i] = FALSE;
3705 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3706 This->fixed_function_usage_map[i+1] = TRUE;
3711 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3712 int i, tex;
3714 device_update_fixed_function_usage_map(This);
3716 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3717 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3718 if (!This->fixed_function_usage_map[i]) continue;
3720 if (This->texUnitMap[i] != i) {
3721 device_map_stage(This, i, i);
3722 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3723 markTextureStagesDirty(This, i);
3726 return;
3729 /* Now work out the mapping */
3730 tex = 0;
3731 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3732 if (!This->fixed_function_usage_map[i]) continue;
3734 if (This->texUnitMap[i] != tex) {
3735 device_map_stage(This, i, tex);
3736 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3737 markTextureStagesDirty(This, i);
3740 ++tex;
3744 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3745 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3746 int i;
3748 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3749 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3750 device_map_stage(This, i, i);
3751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3752 if (i < MAX_TEXTURES) {
3753 markTextureStagesDirty(This, i);
3759 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3760 int current_mapping = This->rev_tex_unit_map[unit];
3762 if (current_mapping == -1) {
3763 /* Not currently used */
3764 return TRUE;
3767 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3768 /* Used by a fragment sampler */
3770 if (!pshader_sampler_tokens) {
3771 /* No pixel shader, check fixed function */
3772 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3775 /* Pixel shader, check the shader's sampler map */
3776 return !pshader_sampler_tokens[current_mapping];
3779 /* Used by a vertex sampler */
3780 return !vshader_sampler_tokens[current_mapping];
3783 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3784 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3785 DWORD *pshader_sampler_tokens = NULL;
3786 int start = GL_LIMITS(combined_samplers) - 1;
3787 int i;
3789 if (ps) {
3790 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3792 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3793 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3794 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3797 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3798 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3799 if (vshader_sampler_tokens[i]) {
3800 if (This->texUnitMap[vsampler_idx] != -1) {
3801 /* Already mapped somewhere */
3802 continue;
3805 while (start >= 0) {
3806 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3807 device_map_stage(This, vsampler_idx, start);
3808 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3810 --start;
3811 break;
3814 --start;
3820 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3821 BOOL vs = use_vs(This);
3822 BOOL ps = use_ps(This);
3824 * Rules are:
3825 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3826 * that would be really messy and require shader recompilation
3827 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3828 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3830 if (ps) {
3831 device_map_psamplers(This);
3832 } else {
3833 device_map_fixed_function_samplers(This);
3836 if (vs) {
3837 device_map_vsamplers(This, ps);
3841 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3842 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3843 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3844 This->updateStateBlock->pixelShader = pShader;
3845 This->updateStateBlock->changed.pixelShader = TRUE;
3847 /* Handle recording of state blocks */
3848 if (This->isRecordingState) {
3849 TRACE("Recording... not performing anything\n");
3852 if (This->isRecordingState) {
3853 TRACE("Recording... not performing anything\n");
3854 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3855 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3856 return WINED3D_OK;
3859 if(pShader == oldShader) {
3860 TRACE("App is setting the old pixel shader over, nothing to do\n");
3861 return WINED3D_OK;
3864 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3865 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3867 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3868 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3870 return WINED3D_OK;
3873 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3874 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3876 if (NULL == ppShader) {
3877 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3878 return WINED3DERR_INVALIDCALL;
3881 *ppShader = This->stateBlock->pixelShader;
3882 if (NULL != *ppShader) {
3883 IWineD3DPixelShader_AddRef(*ppShader);
3885 TRACE("(%p) : returning %p\n", This, *ppShader);
3886 return WINED3D_OK;
3889 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3890 IWineD3DDevice *iface,
3891 UINT start,
3892 CONST BOOL *srcData,
3893 UINT count) {
3895 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3896 int i, cnt = min(count, MAX_CONST_B - start);
3898 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3899 iface, srcData, start, count);
3901 if (srcData == NULL || cnt < 0)
3902 return WINED3DERR_INVALIDCALL;
3904 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3905 for (i = 0; i < cnt; i++)
3906 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3908 for (i = start; i < cnt + start; ++i) {
3909 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3912 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3914 return WINED3D_OK;
3917 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3918 IWineD3DDevice *iface,
3919 UINT start,
3920 BOOL *dstData,
3921 UINT count) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3924 int cnt = min(count, MAX_CONST_B - start);
3926 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3927 iface, dstData, start, count);
3929 if (dstData == NULL || cnt < 0)
3930 return WINED3DERR_INVALIDCALL;
3932 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3933 return WINED3D_OK;
3936 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3937 IWineD3DDevice *iface,
3938 UINT start,
3939 CONST int *srcData,
3940 UINT count) {
3942 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 int i, cnt = min(count, MAX_CONST_I - start);
3945 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3946 iface, srcData, start, count);
3948 if (srcData == NULL || cnt < 0)
3949 return WINED3DERR_INVALIDCALL;
3951 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3952 for (i = 0; i < cnt; i++)
3953 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3954 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3956 for (i = start; i < cnt + start; ++i) {
3957 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
3960 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3962 return WINED3D_OK;
3965 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
3966 IWineD3DDevice *iface,
3967 UINT start,
3968 int *dstData,
3969 UINT count) {
3971 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3972 int cnt = min(count, MAX_CONST_I - start);
3974 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3975 iface, dstData, start, count);
3977 if (dstData == NULL || cnt < 0)
3978 return WINED3DERR_INVALIDCALL;
3980 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3981 return WINED3D_OK;
3984 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
3985 IWineD3DDevice *iface,
3986 UINT start,
3987 CONST float *srcData,
3988 UINT count) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 int i;
3993 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3994 iface, srcData, start, count);
3996 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3997 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
3998 return WINED3DERR_INVALIDCALL;
4000 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4001 if(TRACE_ON(d3d)) {
4002 for (i = 0; i < count; i++)
4003 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4004 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4007 for (i = start; i < count + start; ++i) {
4008 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4009 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4010 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4011 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4012 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4014 ptr->idx[ptr->count++] = i;
4015 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4019 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4021 return WINED3D_OK;
4024 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4025 IWineD3DDevice *iface,
4026 UINT start,
4027 CONST float *srcData,
4028 UINT count) {
4030 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4031 int i;
4033 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4034 iface, srcData, start, count);
4036 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4037 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4038 return WINED3DERR_INVALIDCALL;
4040 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4041 if(TRACE_ON(d3d)) {
4042 for (i = 0; i < count; i++)
4043 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4044 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4047 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4048 * context. On a context switch the old context will be fully dirtified
4050 memset(This->activeContext->pshader_const_dirty + start, 1,
4051 sizeof(*This->activeContext->pshader_const_dirty) * count);
4052 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4054 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4056 return WINED3D_OK;
4059 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4060 IWineD3DDevice *iface,
4061 UINT start,
4062 float *dstData,
4063 UINT count) {
4065 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4066 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4068 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4069 iface, dstData, start, count);
4071 if (dstData == NULL || cnt < 0)
4072 return WINED3DERR_INVALIDCALL;
4074 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4075 return WINED3D_OK;
4078 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4079 static HRESULT
4080 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4081 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4082 unsigned int i;
4083 DWORD DestFVF = dest->fvf;
4084 WINED3DVIEWPORT vp;
4085 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4086 BOOL doClip;
4087 int numTextures;
4089 if (lpStrideData->u.s.normal.lpData) {
4090 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4093 if (lpStrideData->u.s.position.lpData == NULL) {
4094 ERR("Source has no position mask\n");
4095 return WINED3DERR_INVALIDCALL;
4098 /* We might access VBOs from this code, so hold the lock */
4099 ENTER_GL();
4101 if (dest->resource.allocatedMemory == NULL) {
4102 /* This may happen if we do direct locking into a vbo. Unlikely,
4103 * but theoretically possible(ddraw processvertices test)
4105 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4106 if(!dest->resource.allocatedMemory) {
4107 LEAVE_GL();
4108 ERR("Out of memory\n");
4109 return E_OUTOFMEMORY;
4111 if(dest->vbo) {
4112 void *src;
4113 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4114 checkGLcall("glBindBufferARB");
4115 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4116 if(src) {
4117 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4119 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4120 checkGLcall("glUnmapBufferARB");
4124 /* Get a pointer into the destination vbo(create one if none exists) and
4125 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4127 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4128 dest->Flags |= VBFLAG_CREATEVBO;
4129 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4132 if(dest->vbo) {
4133 unsigned char extrabytes = 0;
4134 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4135 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4136 * this may write 4 extra bytes beyond the area that should be written
4138 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4139 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4140 if(!dest_conv_addr) {
4141 ERR("Out of memory\n");
4142 /* Continue without storing converted vertices */
4144 dest_conv = dest_conv_addr;
4147 /* Should I clip?
4148 * a) WINED3DRS_CLIPPING is enabled
4149 * b) WINED3DVOP_CLIP is passed
4151 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4152 static BOOL warned = FALSE;
4154 * The clipping code is not quite correct. Some things need
4155 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4156 * so disable clipping for now.
4157 * (The graphics in Half-Life are broken, and my processvertices
4158 * test crashes with IDirect3DDevice3)
4159 doClip = TRUE;
4161 doClip = FALSE;
4162 if(!warned) {
4163 warned = TRUE;
4164 FIXME("Clipping is broken and disabled for now\n");
4166 } else doClip = FALSE;
4167 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4169 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4170 WINED3DTS_VIEW,
4171 &view_mat);
4172 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4173 WINED3DTS_PROJECTION,
4174 &proj_mat);
4175 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4176 WINED3DTS_WORLDMATRIX(0),
4177 &world_mat);
4179 TRACE("View mat:\n");
4180 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);
4181 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);
4182 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);
4183 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);
4185 TRACE("Proj mat:\n");
4186 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);
4187 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);
4188 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);
4189 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);
4191 TRACE("World mat:\n");
4192 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);
4193 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);
4194 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);
4195 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);
4197 /* Get the viewport */
4198 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4199 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4200 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4202 multiply_matrix(&mat,&view_mat,&world_mat);
4203 multiply_matrix(&mat,&proj_mat,&mat);
4205 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4207 for (i = 0; i < dwCount; i+= 1) {
4208 unsigned int tex_index;
4210 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4211 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4212 /* The position first */
4213 float *p =
4214 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4215 float x, y, z, rhw;
4216 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4218 /* Multiplication with world, view and projection matrix */
4219 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);
4220 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);
4221 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);
4222 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);
4224 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4226 /* WARNING: The following things are taken from d3d7 and were not yet checked
4227 * against d3d8 or d3d9!
4230 /* Clipping conditions: From msdn
4232 * A vertex is clipped if it does not match the following requirements
4233 * -rhw < x <= rhw
4234 * -rhw < y <= rhw
4235 * 0 < z <= rhw
4236 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4238 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4239 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4243 if( !doClip ||
4244 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4245 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4246 ( rhw > eps ) ) ) {
4248 /* "Normal" viewport transformation (not clipped)
4249 * 1) The values are divided by rhw
4250 * 2) The y axis is negative, so multiply it with -1
4251 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4252 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4253 * 4) Multiply x with Width/2 and add Width/2
4254 * 5) The same for the height
4255 * 6) Add the viewpoint X and Y to the 2D coordinates and
4256 * The minimum Z value to z
4257 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4259 * Well, basically it's simply a linear transformation into viewport
4260 * coordinates
4263 x /= rhw;
4264 y /= rhw;
4265 z /= rhw;
4267 y *= -1;
4269 x *= vp.Width / 2;
4270 y *= vp.Height / 2;
4271 z *= vp.MaxZ - vp.MinZ;
4273 x += vp.Width / 2 + vp.X;
4274 y += vp.Height / 2 + vp.Y;
4275 z += vp.MinZ;
4277 rhw = 1 / rhw;
4278 } else {
4279 /* That vertex got clipped
4280 * Contrary to OpenGL it is not dropped completely, it just
4281 * undergoes a different calculation.
4283 TRACE("Vertex got clipped\n");
4284 x += rhw;
4285 y += rhw;
4287 x /= 2;
4288 y /= 2;
4290 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4291 * outside of the main vertex buffer memory. That needs some more
4292 * investigation...
4296 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4299 ( (float *) dest_ptr)[0] = x;
4300 ( (float *) dest_ptr)[1] = y;
4301 ( (float *) dest_ptr)[2] = z;
4302 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4304 dest_ptr += 3 * sizeof(float);
4306 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4307 dest_ptr += sizeof(float);
4310 if(dest_conv) {
4311 float w = 1 / rhw;
4312 ( (float *) dest_conv)[0] = x * w;
4313 ( (float *) dest_conv)[1] = y * w;
4314 ( (float *) dest_conv)[2] = z * w;
4315 ( (float *) dest_conv)[3] = w;
4317 dest_conv += 3 * sizeof(float);
4319 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4320 dest_conv += sizeof(float);
4324 if (DestFVF & WINED3DFVF_PSIZE) {
4325 dest_ptr += sizeof(DWORD);
4326 if(dest_conv) dest_conv += sizeof(DWORD);
4328 if (DestFVF & WINED3DFVF_NORMAL) {
4329 float *normal =
4330 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4331 /* AFAIK this should go into the lighting information */
4332 FIXME("Didn't expect the destination to have a normal\n");
4333 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4334 if(dest_conv) {
4335 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4339 if (DestFVF & WINED3DFVF_DIFFUSE) {
4340 DWORD *color_d =
4341 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4342 if(!color_d) {
4343 static BOOL warned = FALSE;
4345 if(!warned) {
4346 ERR("No diffuse color in source, but destination has one\n");
4347 warned = TRUE;
4350 *( (DWORD *) dest_ptr) = 0xffffffff;
4351 dest_ptr += sizeof(DWORD);
4353 if(dest_conv) {
4354 *( (DWORD *) dest_conv) = 0xffffffff;
4355 dest_conv += sizeof(DWORD);
4358 else {
4359 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4360 if(dest_conv) {
4361 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4362 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4363 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4364 dest_conv += sizeof(DWORD);
4369 if (DestFVF & WINED3DFVF_SPECULAR) {
4370 /* What's the color value in the feedback buffer? */
4371 DWORD *color_s =
4372 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4373 if(!color_s) {
4374 static BOOL warned = FALSE;
4376 if(!warned) {
4377 ERR("No specular color in source, but destination has one\n");
4378 warned = TRUE;
4381 *( (DWORD *) dest_ptr) = 0xFF000000;
4382 dest_ptr += sizeof(DWORD);
4384 if(dest_conv) {
4385 *( (DWORD *) dest_conv) = 0xFF000000;
4386 dest_conv += sizeof(DWORD);
4389 else {
4390 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4391 if(dest_conv) {
4392 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4393 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4394 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4395 dest_conv += sizeof(DWORD);
4400 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4401 float *tex_coord =
4402 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4403 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4404 if(!tex_coord) {
4405 ERR("No source texture, but destination requests one\n");
4406 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4407 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4409 else {
4410 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4411 if(dest_conv) {
4412 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4418 if(dest_conv) {
4419 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4420 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4421 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4422 dwCount * get_flexible_vertex_size(DestFVF),
4423 dest_conv_addr));
4424 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4425 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4428 LEAVE_GL();
4430 return WINED3D_OK;
4432 #undef copy_and_next
4434 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4435 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4436 WineDirect3DVertexStridedData strided;
4437 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4438 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4440 if(pVertexDecl) {
4441 ERR("Output vertex declaration not implemented yet\n");
4444 /* Need any context to write to the vbo. */
4445 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4447 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4448 * control the streamIsUP flag, thus restore it afterwards.
4450 This->stateBlock->streamIsUP = FALSE;
4451 memset(&strided, 0, sizeof(strided));
4452 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4453 This->stateBlock->streamIsUP = streamWasUP;
4455 if(vbo || SrcStartIndex) {
4456 unsigned int i;
4457 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4458 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4460 * Also get the start index in, but only loop over all elements if there's something to add at all.
4462 #define FIXSRC(type) \
4463 if(strided.u.s.type.VBO) { \
4464 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4465 strided.u.s.type.VBO = 0; \
4466 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4467 ENTER_GL(); \
4468 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4469 vb->vbo = 0; \
4470 LEAVE_GL(); \
4472 if(strided.u.s.type.lpData) { \
4473 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4475 FIXSRC(position);
4476 FIXSRC(blendWeights);
4477 FIXSRC(blendMatrixIndices);
4478 FIXSRC(normal);
4479 FIXSRC(pSize);
4480 FIXSRC(diffuse);
4481 FIXSRC(specular);
4482 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4483 FIXSRC(texCoords[i]);
4485 FIXSRC(position2);
4486 FIXSRC(normal2);
4487 FIXSRC(tangent);
4488 FIXSRC(binormal);
4489 FIXSRC(tessFactor);
4490 FIXSRC(fog);
4491 FIXSRC(depth);
4492 FIXSRC(sample);
4493 #undef FIXSRC
4496 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4499 /*****
4500 * Get / Set Texture Stage States
4501 * TODO: Verify against dx9 definitions
4502 *****/
4503 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4504 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4505 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4507 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4509 if (Stage >= MAX_TEXTURES) {
4510 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4511 return WINED3D_OK;
4514 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4515 This->updateStateBlock->textureState[Stage][Type] = Value;
4517 if (This->isRecordingState) {
4518 TRACE("Recording... not performing anything\n");
4519 return WINED3D_OK;
4522 /* Checked after the assignments to allow proper stateblock recording */
4523 if(oldValue == Value) {
4524 TRACE("App is setting the old value over, nothing to do\n");
4525 return WINED3D_OK;
4528 if(Stage > This->stateBlock->lowest_disabled_stage &&
4529 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4530 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4531 * Changes in other states are important on disabled stages too
4533 return WINED3D_OK;
4536 if(Type == WINED3DTSS_COLOROP) {
4537 int i;
4539 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4540 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4541 * they have to be disabled
4543 * The current stage is dirtified below.
4545 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4546 TRACE("Additionally dirtifying stage %d\n", i);
4547 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4549 This->stateBlock->lowest_disabled_stage = Stage;
4550 TRACE("New lowest disabled: %d\n", Stage);
4551 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4552 /* Previously disabled stage enabled. Stages above it may need enabling
4553 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4554 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4556 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4559 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4560 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4561 break;
4563 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4564 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4566 This->stateBlock->lowest_disabled_stage = i;
4567 TRACE("New lowest disabled: %d\n", i);
4569 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4570 /* TODO: Built a stage -> texture unit mapping for register combiners */
4574 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4576 return WINED3D_OK;
4579 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4580 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4581 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4582 *pValue = This->updateStateBlock->textureState[Stage][Type];
4583 return WINED3D_OK;
4586 /*****
4587 * Get / Set Texture
4588 *****/
4589 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4590 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4591 IWineD3DBaseTexture *oldTexture;
4593 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4595 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4596 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4599 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4600 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4601 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4604 oldTexture = This->updateStateBlock->textures[Stage];
4606 if(pTexture != NULL) {
4607 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4609 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4610 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4611 return WINED3DERR_INVALIDCALL;
4613 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4616 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4617 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4619 This->updateStateBlock->changed.textures[Stage] = TRUE;
4620 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4621 This->updateStateBlock->textures[Stage] = pTexture;
4623 /* Handle recording of state blocks */
4624 if (This->isRecordingState) {
4625 TRACE("Recording... not performing anything\n");
4626 return WINED3D_OK;
4629 if(oldTexture == pTexture) {
4630 TRACE("App is setting the same texture again, nothing to do\n");
4631 return WINED3D_OK;
4634 /** NOTE: MSDN says that setTexture increases the reference count,
4635 * and that the application must set the texture back to null (or have a leaky application),
4636 * This means we should pass the refcount up to the parent
4637 *******************************/
4638 if (NULL != This->updateStateBlock->textures[Stage]) {
4639 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4640 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4642 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4643 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4644 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4645 * so the COLOROP and ALPHAOP have to be dirtified.
4647 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4648 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4650 if(bindCount == 1) {
4651 new->baseTexture.sampler = Stage;
4653 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4657 if (NULL != oldTexture) {
4658 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4659 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4661 IWineD3DBaseTexture_Release(oldTexture);
4662 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4663 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4664 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4667 if(bindCount && old->baseTexture.sampler == Stage) {
4668 int i;
4669 /* Have to do a search for the other sampler(s) where the texture is bound to
4670 * Shouldn't happen as long as apps bind a texture only to one stage
4672 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4673 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4674 if(This->updateStateBlock->textures[i] == oldTexture) {
4675 old->baseTexture.sampler = i;
4676 break;
4682 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4684 return WINED3D_OK;
4687 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4688 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4690 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4692 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4693 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4696 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4697 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4698 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4701 *ppTexture=This->stateBlock->textures[Stage];
4702 if (*ppTexture)
4703 IWineD3DBaseTexture_AddRef(*ppTexture);
4705 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4707 return WINED3D_OK;
4710 /*****
4711 * Get Back Buffer
4712 *****/
4713 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4714 IWineD3DSurface **ppBackBuffer) {
4715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4716 IWineD3DSwapChain *swapChain;
4717 HRESULT hr;
4719 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4721 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4722 if (hr == WINED3D_OK) {
4723 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4724 IWineD3DSwapChain_Release(swapChain);
4725 } else {
4726 *ppBackBuffer = NULL;
4728 return hr;
4731 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4732 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4733 WARN("(%p) : stub, calling idirect3d for now\n", This);
4734 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4737 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4738 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 IWineD3DSwapChain *swapChain;
4740 HRESULT hr;
4742 if(iSwapChain > 0) {
4743 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4744 if (hr == WINED3D_OK) {
4745 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4746 IWineD3DSwapChain_Release(swapChain);
4747 } else {
4748 FIXME("(%p) Error getting display mode\n", This);
4750 } else {
4751 /* Don't read the real display mode,
4752 but return the stored mode instead. X11 can't change the color
4753 depth, and some apps are pretty angry if they SetDisplayMode from
4754 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4756 Also don't relay to the swapchain because with ddraw it's possible
4757 that there isn't a swapchain at all */
4758 pMode->Width = This->ddraw_width;
4759 pMode->Height = This->ddraw_height;
4760 pMode->Format = This->ddraw_format;
4761 pMode->RefreshRate = 0;
4762 hr = WINED3D_OK;
4765 return hr;
4768 static HRESULT WINAPI IWineD3DDeviceImpl_SetHWND(IWineD3DDevice *iface, HWND hWnd) {
4769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4770 TRACE("(%p)->(%p)\n", This, hWnd);
4772 if(This->ddraw_fullscreen) {
4773 if(This->ddraw_window && This->ddraw_window != hWnd) {
4774 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
4776 if(hWnd && This->ddraw_window != hWnd) {
4777 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, hWnd);
4781 This->ddraw_window = hWnd;
4782 return WINED3D_OK;
4785 static HRESULT WINAPI IWineD3DDeviceImpl_GetHWND(IWineD3DDevice *iface, HWND *hWnd) {
4786 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4787 TRACE("(%p)->(%p)\n", This, hWnd);
4789 *hWnd = This->ddraw_window;
4790 return WINED3D_OK;
4793 /*****
4794 * Stateblock related functions
4795 *****/
4797 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4799 IWineD3DStateBlockImpl *object;
4800 HRESULT temp_result;
4801 int i;
4803 TRACE("(%p)\n", This);
4805 if (This->isRecordingState) {
4806 return WINED3DERR_INVALIDCALL;
4809 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4810 if (NULL == object ) {
4811 FIXME("(%p)Error allocating memory for stateblock\n", This);
4812 return E_OUTOFMEMORY;
4814 TRACE("(%p) created object %p\n", This, object);
4815 object->wineD3DDevice= This;
4816 /** FIXME: object->parent = parent; **/
4817 object->parent = NULL;
4818 object->blockType = WINED3DSBT_RECORDED;
4819 object->ref = 1;
4820 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4822 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4823 list_init(&object->lightMap[i]);
4826 temp_result = allocate_shader_constants(object);
4827 if (WINED3D_OK != temp_result)
4828 return temp_result;
4830 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4831 This->updateStateBlock = object;
4832 This->isRecordingState = TRUE;
4834 TRACE("(%p) recording stateblock %p\n",This , object);
4835 return WINED3D_OK;
4838 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4839 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4840 unsigned int i, j;
4841 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4843 if (!This->isRecordingState) {
4844 FIXME("(%p) not recording! returning error\n", This);
4845 *ppStateBlock = NULL;
4846 return WINED3DERR_INVALIDCALL;
4849 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4850 if(object->changed.renderState[i]) {
4851 object->contained_render_states[object->num_contained_render_states] = i;
4852 object->num_contained_render_states++;
4855 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4856 if(object->changed.transform[i]) {
4857 object->contained_transform_states[object->num_contained_transform_states] = i;
4858 object->num_contained_transform_states++;
4861 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4862 if(object->changed.vertexShaderConstantsF[i]) {
4863 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4864 object->num_contained_vs_consts_f++;
4867 for(i = 0; i < MAX_CONST_I; i++) {
4868 if(object->changed.vertexShaderConstantsI[i]) {
4869 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4870 object->num_contained_vs_consts_i++;
4873 for(i = 0; i < MAX_CONST_B; i++) {
4874 if(object->changed.vertexShaderConstantsB[i]) {
4875 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4876 object->num_contained_vs_consts_b++;
4879 for(i = 0; i < MAX_CONST_I; i++) {
4880 if(object->changed.pixelShaderConstantsI[i]) {
4881 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4882 object->num_contained_ps_consts_i++;
4885 for(i = 0; i < MAX_CONST_B; i++) {
4886 if(object->changed.pixelShaderConstantsB[i]) {
4887 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4888 object->num_contained_ps_consts_b++;
4891 for(i = 0; i < MAX_TEXTURES; i++) {
4892 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4893 if(object->changed.textureState[i][j]) {
4894 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4895 object->contained_tss_states[object->num_contained_tss_states].state = j;
4896 object->num_contained_tss_states++;
4900 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4901 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4902 if(object->changed.samplerState[i][j]) {
4903 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4904 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4905 object->num_contained_sampler_states++;
4910 *ppStateBlock = (IWineD3DStateBlock*) object;
4911 This->isRecordingState = FALSE;
4912 This->updateStateBlock = This->stateBlock;
4913 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4914 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4915 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4916 return WINED3D_OK;
4919 /*****
4920 * Scene related functions
4921 *****/
4922 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4923 /* At the moment we have no need for any functionality at the beginning
4924 of a scene */
4925 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4926 TRACE("(%p)\n", This);
4928 if(This->inScene) {
4929 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4930 return WINED3DERR_INVALIDCALL;
4932 This->inScene = TRUE;
4933 return WINED3D_OK;
4936 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4938 TRACE("(%p)\n", This);
4940 if(!This->inScene) {
4941 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4942 return WINED3DERR_INVALIDCALL;
4945 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4946 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4947 ENTER_GL();
4948 glFlush();
4949 checkGLcall("glFlush");
4950 LEAVE_GL();
4952 This->inScene = FALSE;
4953 return WINED3D_OK;
4956 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4957 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4958 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4959 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4960 IWineD3DSwapChain *swapChain = NULL;
4961 int i;
4962 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4964 TRACE("(%p) Presenting the frame\n", This);
4966 for(i = 0 ; i < swapchains ; i ++) {
4968 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4969 TRACE("presentinng chain %d, %p\n", i, swapChain);
4970 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4971 IWineD3DSwapChain_Release(swapChain);
4974 return WINED3D_OK;
4977 /* Not called from the VTable (internal subroutine) */
4978 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4979 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4980 float Z, DWORD Stencil) {
4981 GLbitfield glMask = 0;
4982 unsigned int i;
4983 WINED3DRECT curRect;
4984 RECT vp_rect;
4985 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4986 UINT drawable_width, drawable_height;
4987 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
4989 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
4990 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
4991 * for the cleared parts, and the untouched parts.
4993 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
4994 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
4995 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
4996 * checking all this if the dest surface is in the drawable anyway.
4998 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
4999 while(1) {
5000 if(vp->X != 0 || vp->Y != 0 ||
5001 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5002 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5003 break;
5005 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5006 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5007 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5008 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5009 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5010 break;
5012 if(Count > 0 && pRects && (
5013 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5014 pRects[0].x2 < target->currentDesc.Width ||
5015 pRects[0].y2 < target->currentDesc.Height)) {
5016 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5017 break;
5019 break;
5023 target->get_drawable_size(target, &drawable_width, &drawable_height);
5025 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5026 ENTER_GL();
5028 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5029 apply_fbo_state((IWineD3DDevice *) This);
5032 /* Only set the values up once, as they are not changing */
5033 if (Flags & WINED3DCLEAR_STENCIL) {
5034 glClearStencil(Stencil);
5035 checkGLcall("glClearStencil");
5036 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5037 glStencilMask(0xFFFFFFFF);
5040 if (Flags & WINED3DCLEAR_ZBUFFER) {
5041 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5042 glDepthMask(GL_TRUE);
5043 glClearDepth(Z);
5044 checkGLcall("glClearDepth");
5045 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5046 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5048 if (vp->X != 0 || vp->Y != 0 ||
5049 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5050 surface_load_ds_location(This->stencilBufferTarget, location);
5052 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5053 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5054 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5055 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5056 surface_load_ds_location(This->stencilBufferTarget, location);
5058 else if (Count > 0 && pRects && (
5059 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5060 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5061 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5062 surface_load_ds_location(This->stencilBufferTarget, location);
5066 if (Flags & WINED3DCLEAR_TARGET) {
5067 TRACE("Clearing screen with glClear to color %x\n", Color);
5068 glClearColor(D3DCOLOR_R(Color),
5069 D3DCOLOR_G(Color),
5070 D3DCOLOR_B(Color),
5071 D3DCOLOR_A(Color));
5072 checkGLcall("glClearColor");
5074 /* Clear ALL colors! */
5075 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5076 glMask = glMask | GL_COLOR_BUFFER_BIT;
5079 vp_rect.left = vp->X;
5080 vp_rect.top = vp->Y;
5081 vp_rect.right = vp->X + vp->Width;
5082 vp_rect.bottom = vp->Y + vp->Height;
5083 if (!(Count > 0 && pRects)) {
5084 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5085 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5087 if(This->render_offscreen) {
5088 glScissor(vp_rect.left, vp_rect.top,
5089 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5090 } else {
5091 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5092 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5094 checkGLcall("glScissor");
5095 glClear(glMask);
5096 checkGLcall("glClear");
5097 } else {
5098 /* Now process each rect in turn */
5099 for (i = 0; i < Count; i++) {
5100 /* Note gl uses lower left, width/height */
5101 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5102 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5103 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5105 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5106 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5107 curRect.x1, (target->currentDesc.Height - curRect.y2),
5108 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5110 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5111 * The rectangle is not cleared, no error is returned, but further rectanlges are
5112 * still cleared if they are valid
5114 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5115 TRACE("Rectangle with negative dimensions, ignoring\n");
5116 continue;
5119 if(This->render_offscreen) {
5120 glScissor(curRect.x1, curRect.y1,
5121 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5122 } else {
5123 glScissor(curRect.x1, drawable_height - curRect.y2,
5124 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5126 checkGLcall("glScissor");
5128 glClear(glMask);
5129 checkGLcall("glClear");
5133 /* Restore the old values (why..?) */
5134 if (Flags & WINED3DCLEAR_STENCIL) {
5135 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5137 if (Flags & WINED3DCLEAR_TARGET) {
5138 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5139 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5140 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5141 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5142 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5144 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5145 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5147 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5148 /* TODO: Move the fbo logic into ModifyLocation() */
5149 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5150 target->Flags |= SFLAG_INTEXTURE;
5153 if (Flags & WINED3DCLEAR_ZBUFFER) {
5154 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5155 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5156 surface_modify_ds_location(This->stencilBufferTarget, location);
5159 LEAVE_GL();
5161 return WINED3D_OK;
5164 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5165 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5166 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5167 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5169 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5170 Count, pRects, Flags, Color, Z, Stencil);
5172 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5173 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5174 /* TODO: What about depth stencil buffers without stencil bits? */
5175 return WINED3DERR_INVALIDCALL;
5178 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5181 /*****
5182 * Drawing functions
5183 *****/
5184 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5185 UINT PrimitiveCount) {
5187 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5189 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5190 debug_d3dprimitivetype(PrimitiveType),
5191 StartVertex, PrimitiveCount);
5193 if(!This->stateBlock->vertexDecl) {
5194 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5195 return WINED3DERR_INVALIDCALL;
5198 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5199 if(This->stateBlock->streamIsUP) {
5200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5201 This->stateBlock->streamIsUP = FALSE;
5204 if(This->stateBlock->loadBaseVertexIndex != 0) {
5205 This->stateBlock->loadBaseVertexIndex = 0;
5206 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5208 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5209 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5210 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5211 return WINED3D_OK;
5214 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5215 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5216 WINED3DPRIMITIVETYPE PrimitiveType,
5217 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5219 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5220 UINT idxStride = 2;
5221 IWineD3DIndexBuffer *pIB;
5222 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5223 GLuint vbo;
5225 pIB = This->stateBlock->pIndexData;
5226 if (!pIB) {
5227 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5228 * without an index buffer set. (The first time at least...)
5229 * D3D8 simply dies, but I doubt it can do much harm to return
5230 * D3DERR_INVALIDCALL there as well. */
5231 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5232 return WINED3DERR_INVALIDCALL;
5235 if(!This->stateBlock->vertexDecl) {
5236 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5237 return WINED3DERR_INVALIDCALL;
5240 if(This->stateBlock->streamIsUP) {
5241 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5242 This->stateBlock->streamIsUP = FALSE;
5244 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5246 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5247 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5248 minIndex, NumVertices, startIndex, primCount);
5250 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5251 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5252 idxStride = 2;
5253 } else {
5254 idxStride = 4;
5257 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5258 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5259 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5262 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5263 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5265 return WINED3D_OK;
5268 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5269 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5270 UINT VertexStreamZeroStride) {
5271 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5272 IWineD3DVertexBuffer *vb;
5274 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5275 debug_d3dprimitivetype(PrimitiveType),
5276 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5278 if(!This->stateBlock->vertexDecl) {
5279 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5280 return WINED3DERR_INVALIDCALL;
5283 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5284 vb = This->stateBlock->streamSource[0];
5285 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5286 if(vb) IWineD3DVertexBuffer_Release(vb);
5287 This->stateBlock->streamOffset[0] = 0;
5288 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5289 This->stateBlock->streamIsUP = TRUE;
5290 This->stateBlock->loadBaseVertexIndex = 0;
5292 /* TODO: Only mark dirty if drawing from a different UP address */
5293 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5295 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5296 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5298 /* MSDN specifies stream zero settings must be set to NULL */
5299 This->stateBlock->streamStride[0] = 0;
5300 This->stateBlock->streamSource[0] = NULL;
5302 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5303 * the new stream sources or use UP drawing again
5305 return WINED3D_OK;
5308 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5309 UINT MinVertexIndex, UINT NumVertices,
5310 UINT PrimitiveCount, CONST void* pIndexData,
5311 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5312 UINT VertexStreamZeroStride) {
5313 int idxStride;
5314 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5315 IWineD3DVertexBuffer *vb;
5316 IWineD3DIndexBuffer *ib;
5318 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5319 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5320 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5321 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5323 if(!This->stateBlock->vertexDecl) {
5324 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5325 return WINED3DERR_INVALIDCALL;
5328 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5329 idxStride = 2;
5330 } else {
5331 idxStride = 4;
5334 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5335 vb = This->stateBlock->streamSource[0];
5336 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5337 if(vb) IWineD3DVertexBuffer_Release(vb);
5338 This->stateBlock->streamIsUP = TRUE;
5339 This->stateBlock->streamOffset[0] = 0;
5340 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5342 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5343 This->stateBlock->baseVertexIndex = 0;
5344 This->stateBlock->loadBaseVertexIndex = 0;
5345 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5346 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5347 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5349 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5351 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5352 This->stateBlock->streamSource[0] = NULL;
5353 This->stateBlock->streamStride[0] = 0;
5354 ib = This->stateBlock->pIndexData;
5355 if(ib) {
5356 IWineD3DIndexBuffer_Release(ib);
5357 This->stateBlock->pIndexData = NULL;
5359 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5360 * SetStreamSource to specify a vertex buffer
5363 return WINED3D_OK;
5366 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5367 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5369 /* Mark the state dirty until we have nicer tracking
5370 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5371 * that value.
5373 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5374 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5375 This->stateBlock->baseVertexIndex = 0;
5376 This->up_strided = DrawPrimStrideData;
5377 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5378 This->up_strided = NULL;
5379 return WINED3D_OK;
5382 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5383 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5384 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5386 /* Mark the state dirty until we have nicer tracking
5387 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5388 * that value.
5390 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5391 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5392 This->stateBlock->streamIsUP = TRUE;
5393 This->stateBlock->baseVertexIndex = 0;
5394 This->up_strided = DrawPrimStrideData;
5395 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5396 This->up_strided = NULL;
5397 return WINED3D_OK;
5400 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5401 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5402 * not callable by the app directly no parameter validation checks are needed here.
5404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5405 WINED3DLOCKED_BOX src;
5406 WINED3DLOCKED_BOX dst;
5407 HRESULT hr;
5408 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5410 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5411 * dirtification to improve loading performance.
5413 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5414 if(FAILED(hr)) return hr;
5415 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5416 if(FAILED(hr)) {
5417 IWineD3DVolume_UnlockBox(pSourceVolume);
5418 return hr;
5421 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5423 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5424 if(FAILED(hr)) {
5425 IWineD3DVolume_UnlockBox(pSourceVolume);
5426 } else {
5427 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5429 return hr;
5432 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5433 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5435 HRESULT hr = WINED3D_OK;
5436 WINED3DRESOURCETYPE sourceType;
5437 WINED3DRESOURCETYPE destinationType;
5438 int i ,levels;
5440 /* TODO: think about moving the code into IWineD3DBaseTexture */
5442 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5444 /* verify that the source and destination textures aren't NULL */
5445 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5446 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5447 This, pSourceTexture, pDestinationTexture);
5448 hr = WINED3DERR_INVALIDCALL;
5451 if (pSourceTexture == pDestinationTexture) {
5452 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5453 This, pSourceTexture, pDestinationTexture);
5454 hr = WINED3DERR_INVALIDCALL;
5456 /* Verify that the source and destination textures are the same type */
5457 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5458 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5460 if (sourceType != destinationType) {
5461 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5462 This);
5463 hr = WINED3DERR_INVALIDCALL;
5466 /* check that both textures have the identical numbers of levels */
5467 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5468 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5469 hr = WINED3DERR_INVALIDCALL;
5472 if (WINED3D_OK == hr) {
5474 /* Make sure that the destination texture is loaded */
5475 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5477 /* Update every surface level of the texture */
5478 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5480 switch (sourceType) {
5481 case WINED3DRTYPE_TEXTURE:
5483 IWineD3DSurface *srcSurface;
5484 IWineD3DSurface *destSurface;
5486 for (i = 0 ; i < levels ; ++i) {
5487 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5488 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5489 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5490 IWineD3DSurface_Release(srcSurface);
5491 IWineD3DSurface_Release(destSurface);
5492 if (WINED3D_OK != hr) {
5493 WARN("(%p) : Call to update surface failed\n", This);
5494 return hr;
5498 break;
5499 case WINED3DRTYPE_CUBETEXTURE:
5501 IWineD3DSurface *srcSurface;
5502 IWineD3DSurface *destSurface;
5503 WINED3DCUBEMAP_FACES faceType;
5505 for (i = 0 ; i < levels ; ++i) {
5506 /* Update each cube face */
5507 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5508 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5509 if (WINED3D_OK != hr) {
5510 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5511 } else {
5512 TRACE("Got srcSurface %p\n", srcSurface);
5514 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5515 if (WINED3D_OK != hr) {
5516 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5517 } else {
5518 TRACE("Got desrSurface %p\n", destSurface);
5520 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5521 IWineD3DSurface_Release(srcSurface);
5522 IWineD3DSurface_Release(destSurface);
5523 if (WINED3D_OK != hr) {
5524 WARN("(%p) : Call to update surface failed\n", This);
5525 return hr;
5530 break;
5532 case WINED3DRTYPE_VOLUMETEXTURE:
5534 IWineD3DVolume *srcVolume = NULL;
5535 IWineD3DVolume *destVolume = NULL;
5537 for (i = 0 ; i < levels ; ++i) {
5538 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5539 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5540 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5541 IWineD3DVolume_Release(srcVolume);
5542 IWineD3DVolume_Release(destVolume);
5543 if (WINED3D_OK != hr) {
5544 WARN("(%p) : Call to update volume failed\n", This);
5545 return hr;
5549 break;
5551 default:
5552 FIXME("(%p) : Unsupported source and destination type\n", This);
5553 hr = WINED3DERR_INVALIDCALL;
5557 return hr;
5560 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5561 IWineD3DSwapChain *swapChain;
5562 HRESULT hr;
5563 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5564 if(hr == WINED3D_OK) {
5565 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5566 IWineD3DSwapChain_Release(swapChain);
5568 return hr;
5571 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5572 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5573 /* return a sensible default */
5574 *pNumPasses = 1;
5575 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5576 FIXME("(%p) : stub\n", This);
5577 return WINED3D_OK;
5580 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5582 int i;
5584 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5585 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5586 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5587 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5592 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5593 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5594 int j;
5595 UINT NewSize;
5596 PALETTEENTRY **palettes;
5598 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5600 if (PaletteNumber >= MAX_PALETTES) {
5601 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5602 return WINED3DERR_INVALIDCALL;
5605 if (PaletteNumber >= This->NumberOfPalettes) {
5606 NewSize = This->NumberOfPalettes;
5607 do {
5608 NewSize *= 2;
5609 } while(PaletteNumber >= NewSize);
5610 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5611 if (!palettes) {
5612 ERR("Out of memory!\n");
5613 return E_OUTOFMEMORY;
5615 This->palettes = palettes;
5616 This->NumberOfPalettes = NewSize;
5619 if (!This->palettes[PaletteNumber]) {
5620 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5621 if (!This->palettes[PaletteNumber]) {
5622 ERR("Out of memory!\n");
5623 return E_OUTOFMEMORY;
5627 for (j = 0; j < 256; ++j) {
5628 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5629 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5630 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5631 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5633 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5634 TRACE("(%p) : returning\n", This);
5635 return WINED3D_OK;
5638 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5640 int j;
5641 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5642 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5643 /* What happens in such situation isn't documented; Native seems to silently abort
5644 on such conditions. Return Invalid Call. */
5645 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5646 return WINED3DERR_INVALIDCALL;
5648 for (j = 0; j < 256; ++j) {
5649 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5650 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5651 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5652 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5654 TRACE("(%p) : returning\n", This);
5655 return WINED3D_OK;
5658 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5660 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5661 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5662 (tested with reference rasterizer). Return Invalid Call. */
5663 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5664 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5665 return WINED3DERR_INVALIDCALL;
5667 /*TODO: stateblocks */
5668 if (This->currentPalette != PaletteNumber) {
5669 This->currentPalette = PaletteNumber;
5670 dirtify_p8_texture_samplers(This);
5672 TRACE("(%p) : returning\n", This);
5673 return WINED3D_OK;
5676 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 if (PaletteNumber == NULL) {
5679 WARN("(%p) : returning Invalid Call\n", This);
5680 return WINED3DERR_INVALIDCALL;
5682 /*TODO: stateblocks */
5683 *PaletteNumber = This->currentPalette;
5684 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5685 return WINED3D_OK;
5688 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 static BOOL showFixmes = TRUE;
5691 if (showFixmes) {
5692 FIXME("(%p) : stub\n", This);
5693 showFixmes = FALSE;
5696 This->softwareVertexProcessing = bSoftware;
5697 return WINED3D_OK;
5701 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5702 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5703 static BOOL showFixmes = TRUE;
5704 if (showFixmes) {
5705 FIXME("(%p) : stub\n", This);
5706 showFixmes = FALSE;
5708 return This->softwareVertexProcessing;
5712 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5713 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5714 IWineD3DSwapChain *swapChain;
5715 HRESULT hr;
5717 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5719 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5720 if(hr == WINED3D_OK){
5721 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5722 IWineD3DSwapChain_Release(swapChain);
5723 }else{
5724 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5726 return hr;
5730 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5731 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5732 static BOOL showfixmes = TRUE;
5733 if(nSegments != 0.0f) {
5734 if( showfixmes) {
5735 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5736 showfixmes = FALSE;
5739 return WINED3D_OK;
5742 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5743 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5744 static BOOL showfixmes = TRUE;
5745 if( showfixmes) {
5746 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5747 showfixmes = FALSE;
5749 return 0.0f;
5752 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5754 /** TODO: remove casts to IWineD3DSurfaceImpl
5755 * NOTE: move code to surface to accomplish this
5756 ****************************************/
5757 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5758 int srcWidth, srcHeight;
5759 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5760 WINED3DFORMAT destFormat, srcFormat;
5761 UINT destSize;
5762 int srcLeft, destLeft, destTop;
5763 WINED3DPOOL srcPool, destPool;
5764 int offset = 0;
5765 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5766 glDescriptor *glDescription = NULL;
5767 GLenum dummy;
5768 int sampler;
5769 int bpp;
5770 CONVERT_TYPES convert = NO_CONVERSION;
5772 WINED3DSURFACE_DESC winedesc;
5774 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5775 memset(&winedesc, 0, sizeof(winedesc));
5776 winedesc.Width = &srcSurfaceWidth;
5777 winedesc.Height = &srcSurfaceHeight;
5778 winedesc.Pool = &srcPool;
5779 winedesc.Format = &srcFormat;
5781 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5783 winedesc.Width = &destSurfaceWidth;
5784 winedesc.Height = &destSurfaceHeight;
5785 winedesc.Pool = &destPool;
5786 winedesc.Format = &destFormat;
5787 winedesc.Size = &destSize;
5789 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5791 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5792 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5793 return WINED3DERR_INVALIDCALL;
5796 /* This call loads the opengl surface directly, instead of copying the surface to the
5797 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5798 * copy in sysmem and use regular surface loading.
5800 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5801 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5802 if(convert != NO_CONVERSION) {
5803 return IWineD3DSurface_BltFast(pDestinationSurface,
5804 pDestPoint ? pDestPoint->x : 0,
5805 pDestPoint ? pDestPoint->y : 0,
5806 pSourceSurface, (RECT *) pSourceRect, 0);
5809 if (destFormat == WINED3DFMT_UNKNOWN) {
5810 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5811 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5813 /* Get the update surface description */
5814 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5817 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5819 ENTER_GL();
5821 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5822 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5823 checkGLcall("glActiveTextureARB");
5826 /* Make sure the surface is loaded and up to date */
5827 IWineD3DSurface_PreLoad(pDestinationSurface);
5829 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5831 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5832 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5833 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5834 srcLeft = pSourceRect ? pSourceRect->left : 0;
5835 destLeft = pDestPoint ? pDestPoint->x : 0;
5836 destTop = pDestPoint ? pDestPoint->y : 0;
5839 /* This function doesn't support compressed textures
5840 the pitch is just bytesPerPixel * width */
5841 if(srcWidth != srcSurfaceWidth || srcLeft ){
5842 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5843 offset += srcLeft * pSrcSurface->bytesPerPixel;
5844 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5846 /* TODO DXT formats */
5848 if(pSourceRect != NULL && pSourceRect->top != 0){
5849 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5851 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5852 ,This
5853 ,glDescription->level
5854 ,destLeft
5855 ,destTop
5856 ,srcWidth
5857 ,srcHeight
5858 ,glDescription->glFormat
5859 ,glDescription->glType
5860 ,IWineD3DSurface_GetData(pSourceSurface)
5863 /* Sanity check */
5864 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5866 /* need to lock the surface to get the data */
5867 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5870 /* TODO: Cube and volume support */
5871 if(rowoffset != 0){
5872 /* not a whole row so we have to do it a line at a time */
5873 int j;
5875 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5876 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5878 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5880 glTexSubImage2D(glDescription->target
5881 ,glDescription->level
5882 ,destLeft
5884 ,srcWidth
5886 ,glDescription->glFormat
5887 ,glDescription->glType
5888 ,data /* could be quicker using */
5890 data += rowoffset;
5893 } else { /* Full width, so just write out the whole texture */
5895 if (WINED3DFMT_DXT1 == destFormat ||
5896 WINED3DFMT_DXT2 == destFormat ||
5897 WINED3DFMT_DXT3 == destFormat ||
5898 WINED3DFMT_DXT4 == destFormat ||
5899 WINED3DFMT_DXT5 == destFormat) {
5900 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5901 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5902 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5903 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5904 } if (destFormat != srcFormat) {
5905 FIXME("Updating mixed format compressed texture is not curretly support\n");
5906 } else {
5907 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5908 glDescription->level,
5909 glDescription->glFormatInternal,
5910 srcWidth,
5911 srcHeight,
5913 destSize,
5914 IWineD3DSurface_GetData(pSourceSurface));
5916 } else {
5917 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5921 } else {
5922 glTexSubImage2D(glDescription->target
5923 ,glDescription->level
5924 ,destLeft
5925 ,destTop
5926 ,srcWidth
5927 ,srcHeight
5928 ,glDescription->glFormat
5929 ,glDescription->glType
5930 ,IWineD3DSurface_GetData(pSourceSurface)
5934 checkGLcall("glTexSubImage2D");
5936 LEAVE_GL();
5938 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5939 sampler = This->rev_tex_unit_map[0];
5940 if (sampler != -1) {
5941 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5944 return WINED3D_OK;
5947 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5948 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5949 struct WineD3DRectPatch *patch;
5950 unsigned int i;
5951 struct list *e;
5952 BOOL found;
5953 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5955 if(!(Handle || pRectPatchInfo)) {
5956 /* TODO: Write a test for the return value, thus the FIXME */
5957 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5958 return WINED3DERR_INVALIDCALL;
5961 if(Handle) {
5962 i = PATCHMAP_HASHFUNC(Handle);
5963 found = FALSE;
5964 LIST_FOR_EACH(e, &This->patches[i]) {
5965 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5966 if(patch->Handle == Handle) {
5967 found = TRUE;
5968 break;
5972 if(!found) {
5973 TRACE("Patch does not exist. Creating a new one\n");
5974 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5975 patch->Handle = Handle;
5976 list_add_head(&This->patches[i], &patch->entry);
5977 } else {
5978 TRACE("Found existing patch %p\n", patch);
5980 } else {
5981 /* Since opengl does not load tesselated vertex attributes into numbered vertex
5982 * attributes we have to tesselate, read back, and draw. This needs a patch
5983 * management structure instance. Create one.
5985 * A possible improvement is to check if a vertex shader is used, and if not directly
5986 * draw the patch.
5988 FIXME("Drawing an uncached patch. This is slow\n");
5989 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5992 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
5993 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
5994 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
5995 HRESULT hr;
5996 TRACE("Tesselation density or patch info changed, retesselating\n");
5998 if(pRectPatchInfo) {
5999 patch->RectPatchInfo = *pRectPatchInfo;
6001 patch->numSegs[0] = pNumSegs[0];
6002 patch->numSegs[1] = pNumSegs[1];
6003 patch->numSegs[2] = pNumSegs[2];
6004 patch->numSegs[3] = pNumSegs[3];
6006 hr = tesselate_rectpatch(This, patch);
6007 if(FAILED(hr)) {
6008 WARN("Patch tesselation failed\n");
6010 /* Do not release the handle to store the params of the patch */
6011 if(!Handle) {
6012 HeapFree(GetProcessHeap(), 0, patch);
6014 return hr;
6018 This->currentPatch = patch;
6019 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6020 This->currentPatch = NULL;
6022 /* Destroy uncached patches */
6023 if(!Handle) {
6024 HeapFree(GetProcessHeap(), 0, patch->mem);
6025 HeapFree(GetProcessHeap(), 0, patch);
6027 return WINED3D_OK;
6030 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6032 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6033 FIXME("(%p) : Stub\n", This);
6034 return WINED3D_OK;
6037 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6039 int i;
6040 struct WineD3DRectPatch *patch;
6041 struct list *e;
6042 TRACE("(%p) Handle(%d)\n", This, Handle);
6044 i = PATCHMAP_HASHFUNC(Handle);
6045 LIST_FOR_EACH(e, &This->patches[i]) {
6046 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6047 if(patch->Handle == Handle) {
6048 TRACE("Deleting patch %p\n", patch);
6049 list_remove(&patch->entry);
6050 HeapFree(GetProcessHeap(), 0, patch->mem);
6051 HeapFree(GetProcessHeap(), 0, patch);
6052 return WINED3D_OK;
6056 /* TODO: Write a test for the return value */
6057 FIXME("Attempt to destroy nonexistent patch\n");
6058 return WINED3DERR_INVALIDCALL;
6061 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6062 HRESULT hr;
6063 IWineD3DSwapChain *swapchain;
6065 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6066 if (SUCCEEDED(hr)) {
6067 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6068 return swapchain;
6071 return NULL;
6074 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6075 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6077 if (!*fbo) {
6078 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6079 checkGLcall("glGenFramebuffersEXT()");
6081 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6082 checkGLcall("glBindFramebuffer()");
6085 /* TODO: Handle stencil attachments */
6086 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6087 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6089 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6090 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6091 checkGLcall("glFramebufferRenderbufferEXT()");
6092 } else {
6093 IWineD3DBaseTextureImpl *texture_impl;
6094 GLenum texttarget, target;
6095 GLint old_binding = 0;
6097 texttarget = depth_stencil_impl->glDescription.target;
6098 if(texttarget == GL_TEXTURE_2D) {
6099 target = GL_TEXTURE_2D;
6100 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6101 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6102 target = GL_TEXTURE_RECTANGLE_ARB;
6103 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6104 } else {
6105 target = GL_TEXTURE_CUBE_MAP_ARB;
6106 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6109 IWineD3DSurface_PreLoad(depth_stencil);
6111 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6112 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6113 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6114 glBindTexture(target, old_binding);
6116 /* Update base texture states array */
6117 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6118 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6119 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6120 if (texture_impl->baseTexture.bindCount) {
6121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6124 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6127 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6128 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6129 checkGLcall("glFramebufferTexture2DEXT()");
6133 static void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6134 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6135 IWineD3DBaseTextureImpl *texture_impl;
6136 GLenum texttarget, target;
6137 GLint old_binding;
6139 texttarget = surface_impl->glDescription.target;
6140 if(texttarget == GL_TEXTURE_2D) {
6141 target = GL_TEXTURE_2D;
6142 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6143 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6144 target = GL_TEXTURE_RECTANGLE_ARB;
6145 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6146 } else {
6147 target = GL_TEXTURE_CUBE_MAP_ARB;
6148 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6151 IWineD3DSurface_PreLoad(surface);
6153 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6154 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6155 glBindTexture(target, old_binding);
6157 /* Update base texture states array */
6158 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6159 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6160 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6161 if (texture_impl->baseTexture.bindCount) {
6162 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6165 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6168 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6169 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6171 checkGLcall("attach_surface_fbo");
6174 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6175 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6176 IWineD3DSwapChain *swapchain;
6178 swapchain = get_swapchain(surface);
6179 if (swapchain) {
6180 GLenum buffer;
6182 TRACE("Surface %p is onscreen\n", surface);
6184 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6185 buffer = surface_get_gl_buffer(surface, swapchain);
6186 glDrawBuffer(buffer);
6187 checkGLcall("glDrawBuffer()");
6188 } else {
6189 TRACE("Surface %p is offscreen\n", surface);
6190 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6191 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6192 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6193 checkGLcall("glFramebufferRenderbufferEXT");
6196 if (rect) {
6197 glEnable(GL_SCISSOR_TEST);
6198 if(!swapchain) {
6199 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6200 } else {
6201 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6202 rect->x2 - rect->x1, rect->y2 - rect->y1);
6204 checkGLcall("glScissor");
6205 } else {
6206 glDisable(GL_SCISSOR_TEST);
6208 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6210 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6211 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6213 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6214 glClear(GL_COLOR_BUFFER_BIT);
6215 checkGLcall("glClear");
6217 if (This->render_offscreen) {
6218 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6219 } else {
6220 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6221 checkGLcall("glBindFramebuffer()");
6224 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6225 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6226 glDrawBuffer(GL_BACK);
6227 checkGLcall("glDrawBuffer()");
6231 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6232 unsigned int r, g, b, a;
6233 DWORD ret;
6235 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6236 destfmt == WINED3DFMT_R8G8B8)
6237 return color;
6239 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6241 a = (color & 0xff000000) >> 24;
6242 r = (color & 0x00ff0000) >> 16;
6243 g = (color & 0x0000ff00) >> 8;
6244 b = (color & 0x000000ff) >> 0;
6246 switch(destfmt)
6248 case WINED3DFMT_R5G6B5:
6249 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6250 r = (r * 32) / 256;
6251 g = (g * 64) / 256;
6252 b = (b * 32) / 256;
6253 ret = r << 11;
6254 ret |= g << 5;
6255 ret |= b;
6256 TRACE("Returning %08x\n", ret);
6257 return ret;
6259 case WINED3DFMT_X1R5G5B5:
6260 case WINED3DFMT_A1R5G5B5:
6261 a = (a * 2) / 256;
6262 r = (r * 32) / 256;
6263 g = (g * 32) / 256;
6264 b = (b * 32) / 256;
6265 ret = a << 15;
6266 ret |= r << 10;
6267 ret |= g << 5;
6268 ret |= b << 0;
6269 TRACE("Returning %08x\n", ret);
6270 return ret;
6272 case WINED3DFMT_A8:
6273 TRACE("Returning %08x\n", a);
6274 return a;
6276 case WINED3DFMT_X4R4G4B4:
6277 case WINED3DFMT_A4R4G4B4:
6278 a = (a * 16) / 256;
6279 r = (r * 16) / 256;
6280 g = (g * 16) / 256;
6281 b = (b * 16) / 256;
6282 ret = a << 12;
6283 ret |= r << 8;
6284 ret |= g << 4;
6285 ret |= b << 0;
6286 TRACE("Returning %08x\n", ret);
6287 return ret;
6289 case WINED3DFMT_R3G3B2:
6290 r = (r * 8) / 256;
6291 g = (g * 8) / 256;
6292 b = (b * 4) / 256;
6293 ret = r << 5;
6294 ret |= g << 2;
6295 ret |= b << 0;
6296 TRACE("Returning %08x\n", ret);
6297 return ret;
6299 case WINED3DFMT_X8B8G8R8:
6300 case WINED3DFMT_A8B8G8R8:
6301 ret = a << 24;
6302 ret |= b << 16;
6303 ret |= g << 8;
6304 ret |= r << 0;
6305 TRACE("Returning %08x\n", ret);
6306 return ret;
6308 case WINED3DFMT_A2R10G10B10:
6309 a = (a * 4) / 256;
6310 r = (r * 1024) / 256;
6311 g = (g * 1024) / 256;
6312 b = (b * 1024) / 256;
6313 ret = a << 30;
6314 ret |= r << 20;
6315 ret |= g << 10;
6316 ret |= b << 0;
6317 TRACE("Returning %08x\n", ret);
6318 return ret;
6320 case WINED3DFMT_A2B10G10R10:
6321 a = (a * 4) / 256;
6322 r = (r * 1024) / 256;
6323 g = (g * 1024) / 256;
6324 b = (b * 1024) / 256;
6325 ret = a << 30;
6326 ret |= b << 20;
6327 ret |= g << 10;
6328 ret |= r << 0;
6329 TRACE("Returning %08x\n", ret);
6330 return ret;
6332 default:
6333 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6334 return 0;
6338 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6339 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6340 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6341 WINEDDBLTFX BltFx;
6342 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6344 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6345 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6346 return WINED3DERR_INVALIDCALL;
6349 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6350 ENTER_GL();
6351 color_fill_fbo(iface, pSurface, pRect, color);
6352 LEAVE_GL();
6353 return WINED3D_OK;
6354 } else {
6355 /* Just forward this to the DirectDraw blitting engine */
6356 memset(&BltFx, 0, sizeof(BltFx));
6357 BltFx.dwSize = sizeof(BltFx);
6358 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6359 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6363 /* rendertarget and depth stencil functions */
6364 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6365 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6367 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6368 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6369 return WINED3DERR_INVALIDCALL;
6372 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6373 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6374 /* Note inc ref on returned surface */
6375 if(*ppRenderTarget != NULL)
6376 IWineD3DSurface_AddRef(*ppRenderTarget);
6377 return WINED3D_OK;
6380 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6382 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6383 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6384 IWineD3DSwapChainImpl *Swapchain;
6385 HRESULT hr;
6387 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6389 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6390 if(hr != WINED3D_OK) {
6391 ERR("Can't get the swapchain\n");
6392 return hr;
6395 /* Make sure to release the swapchain */
6396 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6398 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6399 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6400 return WINED3DERR_INVALIDCALL;
6402 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6403 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6404 return WINED3DERR_INVALIDCALL;
6407 if(Swapchain->frontBuffer != Front) {
6408 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6410 if(Swapchain->frontBuffer)
6411 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6412 Swapchain->frontBuffer = Front;
6414 if(Swapchain->frontBuffer) {
6415 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6419 if(Back && !Swapchain->backBuffer) {
6420 /* We need memory for the back buffer array - only one back buffer this way */
6421 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6422 if(!Swapchain->backBuffer) {
6423 ERR("Out of memory\n");
6424 return E_OUTOFMEMORY;
6428 if(Swapchain->backBuffer[0] != Back) {
6429 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6431 /* What to do about the context here in the case of multithreading? Not sure.
6432 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6434 ENTER_GL();
6435 if(!Swapchain->backBuffer[0]) {
6436 /* GL was told to draw to the front buffer at creation,
6437 * undo that
6439 glDrawBuffer(GL_BACK);
6440 checkGLcall("glDrawBuffer(GL_BACK)");
6441 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6442 Swapchain->presentParms.BackBufferCount = 1;
6443 } else if (!Back) {
6444 /* That makes problems - disable for now */
6445 /* glDrawBuffer(GL_FRONT); */
6446 checkGLcall("glDrawBuffer(GL_FRONT)");
6447 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6448 Swapchain->presentParms.BackBufferCount = 0;
6450 LEAVE_GL();
6452 if(Swapchain->backBuffer[0])
6453 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6454 Swapchain->backBuffer[0] = Back;
6456 if(Swapchain->backBuffer[0]) {
6457 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6458 } else {
6459 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6460 Swapchain->backBuffer = NULL;
6465 return WINED3D_OK;
6468 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6469 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6470 *ppZStencilSurface = This->stencilBufferTarget;
6471 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6473 if(*ppZStencilSurface != NULL) {
6474 /* Note inc ref on returned surface */
6475 IWineD3DSurface_AddRef(*ppZStencilSurface);
6476 return WINED3D_OK;
6477 } else {
6478 return WINED3DERR_NOTFOUND;
6482 /* TODO: Handle stencil attachments */
6483 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6486 TRACE("Set depth stencil to %p\n", depth_stencil);
6488 if (depth_stencil) {
6489 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6490 } else {
6491 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6492 checkGLcall("glFramebufferTexture2DEXT()");
6496 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6499 TRACE("Set render target %u to %p\n", idx, render_target);
6501 if (render_target) {
6502 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6503 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6504 } else {
6505 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6506 checkGLcall("glFramebufferTexture2DEXT()");
6508 This->draw_buffers[idx] = GL_NONE;
6512 static void check_fbo_status(IWineD3DDevice *iface) {
6513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6514 GLenum status;
6516 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6517 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6518 TRACE("FBO complete\n");
6519 } else {
6520 IWineD3DSurfaceImpl *attachment;
6521 int i;
6522 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6524 /* Dump the FBO attachments */
6525 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6526 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6527 if (attachment) {
6528 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6529 attachment->pow2Width, attachment->pow2Height);
6532 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6533 if (attachment) {
6534 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6535 attachment->pow2Width, attachment->pow2Height);
6540 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6541 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6542 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6543 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6545 if (!ds_impl) return FALSE;
6547 if (ds_impl->current_renderbuffer) {
6548 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6549 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6552 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6553 rt_impl->pow2Height != ds_impl->pow2Height);
6556 void apply_fbo_state(IWineD3DDevice *iface) {
6557 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6558 unsigned int i;
6560 if (This->render_offscreen) {
6561 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6563 /* Apply render targets */
6564 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6565 IWineD3DSurface *render_target = This->render_targets[i];
6566 if (This->fbo_color_attachments[i] != render_target) {
6567 set_render_target_fbo(iface, i, render_target);
6568 This->fbo_color_attachments[i] = render_target;
6572 /* Apply depth targets */
6573 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6574 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6575 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6577 if (This->stencilBufferTarget) {
6578 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6580 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6581 This->fbo_depth_attachment = This->stencilBufferTarget;
6584 if (GL_SUPPORT(ARB_DRAW_BUFFERS)) {
6585 GL_EXTCALL(glDrawBuffersARB(GL_LIMITS(buffers), This->draw_buffers));
6586 checkGLcall("glDrawBuffers()");
6587 } else {
6588 glDrawBuffer(This->draw_buffers[0]);
6589 checkGLcall("glDrawBuffer()");
6591 } else {
6592 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6595 check_fbo_status(iface);
6598 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6599 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6600 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6601 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6602 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6603 GLenum gl_filter;
6605 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6606 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6607 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6608 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6610 switch (filter) {
6611 case WINED3DTEXF_LINEAR:
6612 gl_filter = GL_LINEAR;
6613 break;
6615 default:
6616 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6617 case WINED3DTEXF_NONE:
6618 case WINED3DTEXF_POINT:
6619 gl_filter = GL_NEAREST;
6620 break;
6623 /* Attach src surface to src fbo */
6624 src_swapchain = get_swapchain(src_surface);
6625 if (src_swapchain) {
6626 GLenum buffer;
6628 TRACE("Source surface %p is onscreen\n", src_surface);
6629 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6630 /* Make sure the drawable is up to date. In the offscreen case
6631 * attach_surface_fbo() implicitly takes care of this. */
6632 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6634 ENTER_GL();
6635 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6636 buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6637 glReadBuffer(buffer);
6638 checkGLcall("glReadBuffer()");
6640 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6641 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6642 } else {
6643 TRACE("Source surface %p is offscreen\n", src_surface);
6644 ENTER_GL();
6645 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6646 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6647 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6648 checkGLcall("glReadBuffer()");
6649 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6650 checkGLcall("glFramebufferRenderbufferEXT");
6652 LEAVE_GL();
6654 /* Attach dst surface to dst fbo */
6655 dst_swapchain = get_swapchain(dst_surface);
6656 if (dst_swapchain) {
6657 GLenum buffer;
6659 TRACE("Destination surface %p is onscreen\n", dst_surface);
6660 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6661 /* Make sure the drawable is up to date. In the offscreen case
6662 * attach_surface_fbo() implicitly takes care of this. */
6663 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6665 ENTER_GL();
6666 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6667 buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6668 glDrawBuffer(buffer);
6669 checkGLcall("glDrawBuffer()");
6671 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6672 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6673 } else {
6674 TRACE("Destination surface %p is offscreen\n", dst_surface);
6676 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6677 if(!src_swapchain) {
6678 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6681 ENTER_GL();
6682 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6683 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6684 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6685 checkGLcall("glDrawBuffer()");
6686 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6687 checkGLcall("glFramebufferRenderbufferEXT");
6689 glDisable(GL_SCISSOR_TEST);
6690 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6692 if (flip) {
6693 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6694 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6695 checkGLcall("glBlitFramebuffer()");
6696 } else {
6697 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6698 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6699 checkGLcall("glBlitFramebuffer()");
6702 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6704 if (This->render_offscreen) {
6705 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6706 } else {
6707 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6708 checkGLcall("glBindFramebuffer()");
6711 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6712 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6713 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6714 glDrawBuffer(GL_BACK);
6715 checkGLcall("glDrawBuffer()");
6717 LEAVE_GL();
6720 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6721 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6722 WINED3DVIEWPORT viewport;
6724 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6726 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6727 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6728 This, RenderTargetIndex, GL_LIMITS(buffers));
6729 return WINED3DERR_INVALIDCALL;
6732 /* MSDN says that null disables the render target
6733 but a device must always be associated with a render target
6734 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6736 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6737 FIXME("Trying to set render target 0 to NULL\n");
6738 return WINED3DERR_INVALIDCALL;
6740 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6741 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);
6742 return WINED3DERR_INVALIDCALL;
6745 /* If we are trying to set what we already have, don't bother */
6746 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6747 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6748 return WINED3D_OK;
6750 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6751 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6752 This->render_targets[RenderTargetIndex] = pRenderTarget;
6754 /* Render target 0 is special */
6755 if(RenderTargetIndex == 0) {
6756 /* Finally, reset the viewport as the MSDN states. */
6757 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6758 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6759 viewport.X = 0;
6760 viewport.Y = 0;
6761 viewport.MaxZ = 1.0f;
6762 viewport.MinZ = 0.0f;
6763 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6764 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6765 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6767 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6769 return WINED3D_OK;
6772 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6774 HRESULT hr = WINED3D_OK;
6775 IWineD3DSurface *tmp;
6777 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6779 if (pNewZStencil == This->stencilBufferTarget) {
6780 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6781 } else {
6782 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6783 * depending on the renter target implementation being used.
6784 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6785 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6786 * stencil buffer and incur an extra memory overhead
6787 ******************************************************/
6789 if (This->stencilBufferTarget) {
6790 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6791 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6792 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6795 tmp = This->stencilBufferTarget;
6796 This->stencilBufferTarget = pNewZStencil;
6797 /* should we be calling the parent or the wined3d surface? */
6798 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6799 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6800 hr = WINED3D_OK;
6802 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6803 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6804 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6805 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6806 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6810 return hr;
6813 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6814 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6815 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6816 /* TODO: the use of Impl is deprecated. */
6817 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6818 WINED3DLOCKED_RECT lockedRect;
6820 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6822 /* some basic validation checks */
6823 if(This->cursorTexture) {
6824 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6825 ENTER_GL();
6826 glDeleteTextures(1, &This->cursorTexture);
6827 LEAVE_GL();
6828 This->cursorTexture = 0;
6831 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6832 This->haveHardwareCursor = TRUE;
6833 else
6834 This->haveHardwareCursor = FALSE;
6836 if(pCursorBitmap) {
6837 WINED3DLOCKED_RECT rect;
6839 /* MSDN: Cursor must be A8R8G8B8 */
6840 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6841 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6842 return WINED3DERR_INVALIDCALL;
6845 /* MSDN: Cursor must be smaller than the display mode */
6846 if(pSur->currentDesc.Width > This->ddraw_width ||
6847 pSur->currentDesc.Height > This->ddraw_height) {
6848 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);
6849 return WINED3DERR_INVALIDCALL;
6852 if (!This->haveHardwareCursor) {
6853 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6855 /* Do not store the surface's pointer because the application may
6856 * release it after setting the cursor image. Windows doesn't
6857 * addref the set surface, so we can't do this either without
6858 * creating circular refcount dependencies. Copy out the gl texture
6859 * instead.
6861 This->cursorWidth = pSur->currentDesc.Width;
6862 This->cursorHeight = pSur->currentDesc.Height;
6863 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6865 const GlPixelFormatDesc *glDesc;
6866 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6867 char *mem, *bits = (char *)rect.pBits;
6868 GLint intfmt = glDesc->glInternal;
6869 GLint format = glDesc->glFormat;
6870 GLint type = glDesc->glType;
6871 INT height = This->cursorHeight;
6872 INT width = This->cursorWidth;
6873 INT bpp = tableEntry->bpp;
6874 INT i, sampler;
6876 /* Reformat the texture memory (pitch and width can be
6877 * different) */
6878 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6879 for(i = 0; i < height; i++)
6880 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6881 IWineD3DSurface_UnlockRect(pCursorBitmap);
6882 ENTER_GL();
6884 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6885 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6886 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6889 /* Make sure that a proper texture unit is selected */
6890 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6891 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6892 checkGLcall("glActiveTextureARB");
6894 sampler = This->rev_tex_unit_map[0];
6895 if (sampler != -1) {
6896 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6898 /* Create a new cursor texture */
6899 glGenTextures(1, &This->cursorTexture);
6900 checkGLcall("glGenTextures");
6901 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6902 checkGLcall("glBindTexture");
6903 /* Copy the bitmap memory into the cursor texture */
6904 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6905 HeapFree(GetProcessHeap(), 0, mem);
6906 checkGLcall("glTexImage2D");
6908 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6909 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6910 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6913 LEAVE_GL();
6915 else
6917 FIXME("A cursor texture was not returned.\n");
6918 This->cursorTexture = 0;
6921 else
6923 /* Draw a hardware cursor */
6924 ICONINFO cursorInfo;
6925 HCURSOR cursor;
6926 /* Create and clear maskBits because it is not needed for
6927 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6928 * chunks. */
6929 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6930 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6931 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6932 WINED3DLOCK_NO_DIRTY_UPDATE |
6933 WINED3DLOCK_READONLY
6935 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6936 pSur->currentDesc.Height);
6938 cursorInfo.fIcon = FALSE;
6939 cursorInfo.xHotspot = XHotSpot;
6940 cursorInfo.yHotspot = YHotSpot;
6941 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6942 pSur->currentDesc.Height, 1,
6943 1, &maskBits);
6944 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6945 pSur->currentDesc.Height, 1,
6946 32, lockedRect.pBits);
6947 IWineD3DSurface_UnlockRect(pCursorBitmap);
6948 /* Create our cursor and clean up. */
6949 cursor = CreateIconIndirect(&cursorInfo);
6950 SetCursor(cursor);
6951 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6952 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6953 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6954 This->hardwareCursor = cursor;
6955 HeapFree(GetProcessHeap(), 0, maskBits);
6959 This->xHotSpot = XHotSpot;
6960 This->yHotSpot = YHotSpot;
6961 return WINED3D_OK;
6964 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
6965 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6966 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
6968 This->xScreenSpace = XScreenSpace;
6969 This->yScreenSpace = YScreenSpace;
6971 return;
6975 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
6976 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6977 BOOL oldVisible = This->bCursorVisible;
6978 POINT pt;
6980 TRACE("(%p) : visible(%d)\n", This, bShow);
6983 * When ShowCursor is first called it should make the cursor appear at the OS's last
6984 * known cursor position. Because of this, some applications just repetitively call
6985 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
6987 GetCursorPos(&pt);
6988 This->xScreenSpace = pt.x;
6989 This->yScreenSpace = pt.y;
6991 if (This->haveHardwareCursor) {
6992 This->bCursorVisible = bShow;
6993 if (bShow)
6994 SetCursor(This->hardwareCursor);
6995 else
6996 SetCursor(NULL);
6998 else
7000 if (This->cursorTexture)
7001 This->bCursorVisible = bShow;
7004 return oldVisible;
7007 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 IWineD3DResourceImpl *resource;
7010 TRACE("(%p) : state (%u)\n", This, This->state);
7012 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7013 switch (This->state) {
7014 case WINED3D_OK:
7015 return WINED3D_OK;
7016 case WINED3DERR_DEVICELOST:
7018 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7019 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7020 return WINED3DERR_DEVICENOTRESET;
7022 return WINED3DERR_DEVICELOST;
7024 case WINED3DERR_DRIVERINTERNALERROR:
7025 return WINED3DERR_DRIVERINTERNALERROR;
7028 /* Unknown state */
7029 return WINED3DERR_DRIVERINTERNALERROR;
7033 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7034 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7035 /** FIXME: Resource tracking needs to be done,
7036 * The closes we can do to this is set the priorities of all managed textures low
7037 * and then reset them.
7038 ***********************************************************/
7039 FIXME("(%p) : stub\n", This);
7040 return WINED3D_OK;
7043 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7044 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7046 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7047 if(surface->Flags & SFLAG_DIBSECTION) {
7048 /* Release the DC */
7049 SelectObject(surface->hDC, surface->dib.holdbitmap);
7050 DeleteDC(surface->hDC);
7051 /* Release the DIB section */
7052 DeleteObject(surface->dib.DIBsection);
7053 surface->dib.bitmap_data = NULL;
7054 surface->resource.allocatedMemory = NULL;
7055 surface->Flags &= ~SFLAG_DIBSECTION;
7057 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7058 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7059 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7060 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7061 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7062 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7063 } else {
7064 surface->pow2Width = surface->pow2Height = 1;
7065 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7066 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7068 surface->glRect.left = 0;
7069 surface->glRect.top = 0;
7070 surface->glRect.right = surface->pow2Width;
7071 surface->glRect.bottom = surface->pow2Height;
7073 if(surface->glDescription.textureName) {
7074 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7075 ENTER_GL();
7076 glDeleteTextures(1, &surface->glDescription.textureName);
7077 LEAVE_GL();
7078 surface->glDescription.textureName = 0;
7079 surface->Flags &= ~SFLAG_CLIENT;
7081 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7082 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7083 surface->Flags |= SFLAG_NONPOW2;
7084 } else {
7085 surface->Flags &= ~SFLAG_NONPOW2;
7087 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7088 surface->resource.allocatedMemory = NULL;
7089 surface->resource.heapMemory = NULL;
7090 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7091 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7092 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7093 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7094 } else {
7095 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7099 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7100 TRACE("Unloading resource %p\n", resource);
7101 IWineD3DResource_UnLoad(resource);
7102 IWineD3DResource_Release(resource);
7103 return S_OK;
7106 static void reset_fbo_state(IWineD3DDevice *iface) {
7107 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7108 unsigned int i;
7110 ENTER_GL();
7111 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7112 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7114 if (This->fbo) {
7115 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7116 This->fbo = 0;
7118 if (This->src_fbo) {
7119 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7120 This->src_fbo = 0;
7122 if (This->dst_fbo) {
7123 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7124 This->dst_fbo = 0;
7126 checkGLcall("Tear down FBOs\n");
7127 LEAVE_GL();
7129 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7130 This->fbo_color_attachments[i] = NULL;
7132 This->fbo_depth_attachment = NULL;
7135 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7136 UINT i, count;
7137 WINED3DDISPLAYMODE m;
7138 HRESULT hr;
7140 /* All Windowed modes are supported, as is leaving the current mode */
7141 if(pp->Windowed) return TRUE;
7142 if(!pp->BackBufferWidth) return TRUE;
7143 if(!pp->BackBufferHeight) return TRUE;
7145 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7146 for(i = 0; i < count; i++) {
7147 memset(&m, 0, sizeof(m));
7148 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7149 if(FAILED(hr)) {
7150 ERR("EnumAdapterModes failed\n");
7152 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7153 /* Mode found, it is supported */
7154 return TRUE;
7157 /* Mode not found -> not supported */
7158 return FALSE;
7161 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7162 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7163 IWineD3DSwapChainImpl *swapchain;
7164 HRESULT hr;
7165 BOOL DisplayModeChanged = FALSE;
7166 WINED3DDISPLAYMODE mode;
7167 IWineD3DBaseShaderImpl *shader;
7168 IWineD3DSurfaceImpl *target;
7169 UINT i;
7170 TRACE("(%p)\n", This);
7172 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7173 if(FAILED(hr)) {
7174 ERR("Failed to get the first implicit swapchain\n");
7175 return hr;
7178 if(!is_display_mode_supported(This, pPresentationParameters)) {
7179 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7180 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7181 pPresentationParameters->BackBufferHeight);
7182 return WINED3DERR_INVALIDCALL;
7185 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7186 * on an existing gl context, so there's no real need for recreation.
7188 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7190 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7192 TRACE("New params:\n");
7193 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7194 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7195 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7196 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7197 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7198 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7199 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7200 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7201 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7202 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7203 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7204 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7205 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7207 /* No special treatment of these parameters. Just store them */
7208 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7209 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7210 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7211 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7213 /* What to do about these? */
7214 if(pPresentationParameters->BackBufferCount != 0 &&
7215 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7216 ERR("Cannot change the back buffer count yet\n");
7218 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7219 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7220 ERR("Cannot change the back buffer format yet\n");
7222 if(pPresentationParameters->hDeviceWindow != NULL &&
7223 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7224 ERR("Cannot change the device window yet\n");
7226 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7227 ERR("What do do about a changed auto depth stencil parameter?\n");
7230 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7231 reset_fbo_state((IWineD3DDevice *) This);
7234 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7235 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7236 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7239 ENTER_GL();
7240 if(This->depth_blt_texture) {
7241 glDeleteTextures(1, &This->depth_blt_texture);
7242 This->depth_blt_texture = 0;
7244 if (This->depth_blt_rb) {
7245 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7246 This->depth_blt_rb = 0;
7247 This->depth_blt_rb_w = 0;
7248 This->depth_blt_rb_h = 0;
7250 This->shader_backend->shader_free_private(iface);
7251 This->frag_pipe->free_private(iface);
7253 for (i = 0; i < GL_LIMITS(textures); i++) {
7254 /* Textures are recreated below */
7255 glDeleteTextures(1, &This->dummyTextureName[i]);
7256 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7257 This->dummyTextureName[i] = 0;
7259 LEAVE_GL();
7261 while(This->numContexts) {
7262 DestroyContext(This, This->contexts[0]);
7264 This->activeContext = NULL;
7265 HeapFree(GetProcessHeap(), 0, swapchain->context);
7266 swapchain->context = NULL;
7267 swapchain->num_contexts = 0;
7269 if(pPresentationParameters->Windowed) {
7270 mode.Width = swapchain->orig_width;
7271 mode.Height = swapchain->orig_height;
7272 mode.RefreshRate = 0;
7273 mode.Format = swapchain->presentParms.BackBufferFormat;
7274 } else {
7275 mode.Width = pPresentationParameters->BackBufferWidth;
7276 mode.Height = pPresentationParameters->BackBufferHeight;
7277 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7278 mode.Format = swapchain->presentParms.BackBufferFormat;
7280 SetWindowLongA(swapchain->win_handle, GWL_STYLE, WS_POPUP);
7281 SetWindowPos(swapchain->win_handle, HWND_TOP, 0, 0,
7282 pPresentationParameters->BackBufferWidth,
7283 pPresentationParameters->BackBufferHeight, SWP_SHOWWINDOW | SWP_FRAMECHANGED);
7286 /* Should Width == 800 && Height == 0 set 800x600? */
7287 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7288 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7289 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7291 WINED3DVIEWPORT vp;
7292 int i;
7294 vp.X = 0;
7295 vp.Y = 0;
7296 vp.Width = pPresentationParameters->BackBufferWidth;
7297 vp.Height = pPresentationParameters->BackBufferHeight;
7298 vp.MinZ = 0;
7299 vp.MaxZ = 1;
7301 if(!pPresentationParameters->Windowed) {
7302 DisplayModeChanged = TRUE;
7304 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7305 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7307 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7308 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7309 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7311 if(This->auto_depth_stencil_buffer) {
7312 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7316 /* Now set the new viewport */
7317 IWineD3DDevice_SetViewport(iface, &vp);
7320 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7321 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7322 DisplayModeChanged) {
7324 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7325 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7326 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7327 } else if(!pPresentationParameters->Windowed) {
7328 DWORD style = This->style, exStyle = This->exStyle;
7329 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7330 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7331 * Reset to clear up their mess. Guild Wars also loses the device during that.
7333 This->style = 0;
7334 This->exStyle = 0;
7335 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7336 This->style = style;
7337 This->exStyle = exStyle;
7340 /* Recreate the primary swapchain's context */
7341 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7342 if(swapchain->backBuffer) {
7343 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7344 } else {
7345 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7347 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7348 &swapchain->presentParms);
7349 swapchain->num_contexts = 1;
7350 This->activeContext = swapchain->context[0];
7351 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7353 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7354 if(FAILED(hr)) {
7355 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7357 create_dummy_textures(This);
7360 hr = This->shader_backend->shader_alloc_private(iface);
7361 if(FAILED(hr)) {
7362 ERR("Failed to recreate shader private data\n");
7363 return hr;
7365 hr = This->frag_pipe->alloc_private(iface);
7366 if(FAILED(hr)) {
7367 TRACE("Fragment pipeline private data couldn't be allocated\n");
7368 return hr;
7371 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7372 * first use
7374 return WINED3D_OK;
7377 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7378 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7379 /** FIXME: always true at the moment **/
7380 if(!bEnableDialogs) {
7381 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7383 return WINED3D_OK;
7387 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7389 TRACE("(%p) : pParameters %p\n", This, pParameters);
7391 *pParameters = This->createParms;
7392 return WINED3D_OK;
7395 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7396 IWineD3DSwapChain *swapchain;
7398 TRACE("Relaying to swapchain\n");
7400 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7401 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7402 IWineD3DSwapChain_Release(swapchain);
7404 return;
7407 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7408 IWineD3DSwapChain *swapchain;
7410 TRACE("Relaying to swapchain\n");
7412 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7413 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7414 IWineD3DSwapChain_Release(swapchain);
7416 return;
7420 /** ********************************************************
7421 * Notification functions
7422 ** ********************************************************/
7423 /** This function must be called in the release of a resource when ref == 0,
7424 * the contents of resource must still be correct,
7425 * any handles to other resource held by the caller must be closed
7426 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7427 *****************************************************/
7428 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7431 TRACE("(%p) : Adding Resource %p\n", This, resource);
7432 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7435 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7436 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7438 TRACE("(%p) : Removing resource %p\n", This, resource);
7440 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7444 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7445 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7446 int counter;
7448 TRACE("(%p) : resource %p\n", This, resource);
7449 switch(IWineD3DResource_GetType(resource)){
7450 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7451 case WINED3DRTYPE_SURFACE: {
7452 unsigned int i;
7454 /* Cleanup any FBO attachments if d3d is enabled */
7455 if(This->d3d_initialized) {
7456 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7457 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7459 TRACE("Last active render target destroyed\n");
7460 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7461 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7462 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7463 * and the lastActiveRenderTarget member shouldn't matter
7465 if(swapchain) {
7466 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7467 TRACE("Activating primary back buffer\n");
7468 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7469 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7470 /* Single buffering environment */
7471 TRACE("Activating primary front buffer\n");
7472 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7473 } else {
7474 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7475 /* Implicit render target destroyed, that means the device is being destroyed
7476 * whatever we set here, it shouldn't matter
7478 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7480 } else {
7481 /* May happen during ddraw uninitialization */
7482 TRACE("Render target set, but swapchain does not exist!\n");
7483 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7487 ENTER_GL();
7488 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7489 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7490 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7491 set_render_target_fbo(iface, i, NULL);
7492 This->fbo_color_attachments[i] = NULL;
7495 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7496 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7497 set_depth_stencil_fbo(iface, NULL);
7498 This->fbo_depth_attachment = NULL;
7500 LEAVE_GL();
7503 break;
7505 case WINED3DRTYPE_TEXTURE:
7506 case WINED3DRTYPE_CUBETEXTURE:
7507 case WINED3DRTYPE_VOLUMETEXTURE:
7508 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7509 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7510 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7511 This->stateBlock->textures[counter] = NULL;
7513 if (This->updateStateBlock != This->stateBlock ){
7514 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7515 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7516 This->updateStateBlock->textures[counter] = NULL;
7520 break;
7521 case WINED3DRTYPE_VOLUME:
7522 /* TODO: nothing really? */
7523 break;
7524 case WINED3DRTYPE_VERTEXBUFFER:
7525 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7527 int streamNumber;
7528 TRACE("Cleaning up stream pointers\n");
7530 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7531 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7532 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7534 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7535 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7536 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7537 This->updateStateBlock->streamSource[streamNumber] = 0;
7538 /* Set changed flag? */
7541 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) */
7542 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7543 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7544 This->stateBlock->streamSource[streamNumber] = 0;
7547 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7548 else { /* This shouldn't happen */
7549 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7551 #endif
7555 break;
7556 case WINED3DRTYPE_INDEXBUFFER:
7557 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7558 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7559 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7560 This->updateStateBlock->pIndexData = NULL;
7563 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7564 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7565 This->stateBlock->pIndexData = NULL;
7569 break;
7570 default:
7571 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7572 break;
7576 /* Remove the resource from the resourceStore */
7577 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7579 TRACE("Resource released\n");
7583 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7584 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7585 IWineD3DResourceImpl *resource, *cursor;
7586 HRESULT ret;
7587 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7589 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7590 TRACE("enumerating resource %p\n", resource);
7591 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7592 ret = pCallback((IWineD3DResource *) resource, pData);
7593 if(ret == S_FALSE) {
7594 TRACE("Canceling enumeration\n");
7595 break;
7598 return WINED3D_OK;
7601 /**********************************************************
7602 * IWineD3DDevice VTbl follows
7603 **********************************************************/
7605 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7607 /*** IUnknown methods ***/
7608 IWineD3DDeviceImpl_QueryInterface,
7609 IWineD3DDeviceImpl_AddRef,
7610 IWineD3DDeviceImpl_Release,
7611 /*** IWineD3DDevice methods ***/
7612 IWineD3DDeviceImpl_GetParent,
7613 /*** Creation methods**/
7614 IWineD3DDeviceImpl_CreateVertexBuffer,
7615 IWineD3DDeviceImpl_CreateIndexBuffer,
7616 IWineD3DDeviceImpl_CreateStateBlock,
7617 IWineD3DDeviceImpl_CreateSurface,
7618 IWineD3DDeviceImpl_CreateTexture,
7619 IWineD3DDeviceImpl_CreateVolumeTexture,
7620 IWineD3DDeviceImpl_CreateVolume,
7621 IWineD3DDeviceImpl_CreateCubeTexture,
7622 IWineD3DDeviceImpl_CreateQuery,
7623 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7624 IWineD3DDeviceImpl_CreateVertexDeclaration,
7625 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7626 IWineD3DDeviceImpl_CreateVertexShader,
7627 IWineD3DDeviceImpl_CreatePixelShader,
7628 IWineD3DDeviceImpl_CreatePalette,
7629 /*** Odd functions **/
7630 IWineD3DDeviceImpl_Init3D,
7631 IWineD3DDeviceImpl_Uninit3D,
7632 IWineD3DDeviceImpl_SetFullscreen,
7633 IWineD3DDeviceImpl_SetMultithreaded,
7634 IWineD3DDeviceImpl_EvictManagedResources,
7635 IWineD3DDeviceImpl_GetAvailableTextureMem,
7636 IWineD3DDeviceImpl_GetBackBuffer,
7637 IWineD3DDeviceImpl_GetCreationParameters,
7638 IWineD3DDeviceImpl_GetDeviceCaps,
7639 IWineD3DDeviceImpl_GetDirect3D,
7640 IWineD3DDeviceImpl_GetDisplayMode,
7641 IWineD3DDeviceImpl_SetDisplayMode,
7642 IWineD3DDeviceImpl_GetHWND,
7643 IWineD3DDeviceImpl_SetHWND,
7644 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7645 IWineD3DDeviceImpl_GetRasterStatus,
7646 IWineD3DDeviceImpl_GetSwapChain,
7647 IWineD3DDeviceImpl_Reset,
7648 IWineD3DDeviceImpl_SetDialogBoxMode,
7649 IWineD3DDeviceImpl_SetCursorProperties,
7650 IWineD3DDeviceImpl_SetCursorPosition,
7651 IWineD3DDeviceImpl_ShowCursor,
7652 IWineD3DDeviceImpl_TestCooperativeLevel,
7653 /*** Getters and setters **/
7654 IWineD3DDeviceImpl_SetClipPlane,
7655 IWineD3DDeviceImpl_GetClipPlane,
7656 IWineD3DDeviceImpl_SetClipStatus,
7657 IWineD3DDeviceImpl_GetClipStatus,
7658 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7659 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7660 IWineD3DDeviceImpl_SetDepthStencilSurface,
7661 IWineD3DDeviceImpl_GetDepthStencilSurface,
7662 IWineD3DDeviceImpl_SetFVF,
7663 IWineD3DDeviceImpl_GetFVF,
7664 IWineD3DDeviceImpl_SetGammaRamp,
7665 IWineD3DDeviceImpl_GetGammaRamp,
7666 IWineD3DDeviceImpl_SetIndices,
7667 IWineD3DDeviceImpl_GetIndices,
7668 IWineD3DDeviceImpl_SetBaseVertexIndex,
7669 IWineD3DDeviceImpl_GetBaseVertexIndex,
7670 IWineD3DDeviceImpl_SetLight,
7671 IWineD3DDeviceImpl_GetLight,
7672 IWineD3DDeviceImpl_SetLightEnable,
7673 IWineD3DDeviceImpl_GetLightEnable,
7674 IWineD3DDeviceImpl_SetMaterial,
7675 IWineD3DDeviceImpl_GetMaterial,
7676 IWineD3DDeviceImpl_SetNPatchMode,
7677 IWineD3DDeviceImpl_GetNPatchMode,
7678 IWineD3DDeviceImpl_SetPaletteEntries,
7679 IWineD3DDeviceImpl_GetPaletteEntries,
7680 IWineD3DDeviceImpl_SetPixelShader,
7681 IWineD3DDeviceImpl_GetPixelShader,
7682 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7683 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7684 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7685 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7686 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7687 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7688 IWineD3DDeviceImpl_SetRenderState,
7689 IWineD3DDeviceImpl_GetRenderState,
7690 IWineD3DDeviceImpl_SetRenderTarget,
7691 IWineD3DDeviceImpl_GetRenderTarget,
7692 IWineD3DDeviceImpl_SetFrontBackBuffers,
7693 IWineD3DDeviceImpl_SetSamplerState,
7694 IWineD3DDeviceImpl_GetSamplerState,
7695 IWineD3DDeviceImpl_SetScissorRect,
7696 IWineD3DDeviceImpl_GetScissorRect,
7697 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7698 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7699 IWineD3DDeviceImpl_SetStreamSource,
7700 IWineD3DDeviceImpl_GetStreamSource,
7701 IWineD3DDeviceImpl_SetStreamSourceFreq,
7702 IWineD3DDeviceImpl_GetStreamSourceFreq,
7703 IWineD3DDeviceImpl_SetTexture,
7704 IWineD3DDeviceImpl_GetTexture,
7705 IWineD3DDeviceImpl_SetTextureStageState,
7706 IWineD3DDeviceImpl_GetTextureStageState,
7707 IWineD3DDeviceImpl_SetTransform,
7708 IWineD3DDeviceImpl_GetTransform,
7709 IWineD3DDeviceImpl_SetVertexDeclaration,
7710 IWineD3DDeviceImpl_GetVertexDeclaration,
7711 IWineD3DDeviceImpl_SetVertexShader,
7712 IWineD3DDeviceImpl_GetVertexShader,
7713 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7714 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7715 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7716 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7717 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7718 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7719 IWineD3DDeviceImpl_SetViewport,
7720 IWineD3DDeviceImpl_GetViewport,
7721 IWineD3DDeviceImpl_MultiplyTransform,
7722 IWineD3DDeviceImpl_ValidateDevice,
7723 IWineD3DDeviceImpl_ProcessVertices,
7724 /*** State block ***/
7725 IWineD3DDeviceImpl_BeginStateBlock,
7726 IWineD3DDeviceImpl_EndStateBlock,
7727 /*** Scene management ***/
7728 IWineD3DDeviceImpl_BeginScene,
7729 IWineD3DDeviceImpl_EndScene,
7730 IWineD3DDeviceImpl_Present,
7731 IWineD3DDeviceImpl_Clear,
7732 /*** Drawing ***/
7733 IWineD3DDeviceImpl_DrawPrimitive,
7734 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7735 IWineD3DDeviceImpl_DrawPrimitiveUP,
7736 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7737 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7738 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7739 IWineD3DDeviceImpl_DrawRectPatch,
7740 IWineD3DDeviceImpl_DrawTriPatch,
7741 IWineD3DDeviceImpl_DeletePatch,
7742 IWineD3DDeviceImpl_ColorFill,
7743 IWineD3DDeviceImpl_UpdateTexture,
7744 IWineD3DDeviceImpl_UpdateSurface,
7745 IWineD3DDeviceImpl_GetFrontBufferData,
7746 /*** object tracking ***/
7747 IWineD3DDeviceImpl_ResourceReleased,
7748 IWineD3DDeviceImpl_EnumResources
7751 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7753 /*** IUnknown methods ***/
7754 IWineD3DDeviceImpl_QueryInterface,
7755 IWineD3DDeviceImpl_AddRef,
7756 IWineD3DDeviceImpl_Release,
7757 /*** IWineD3DDevice methods ***/
7758 IWineD3DDeviceImpl_GetParent,
7759 /*** Creation methods**/
7760 IWineD3DDeviceImpl_CreateVertexBuffer,
7761 IWineD3DDeviceImpl_CreateIndexBuffer,
7762 IWineD3DDeviceImpl_CreateStateBlock,
7763 IWineD3DDeviceImpl_CreateSurface,
7764 IWineD3DDeviceImpl_CreateTexture,
7765 IWineD3DDeviceImpl_CreateVolumeTexture,
7766 IWineD3DDeviceImpl_CreateVolume,
7767 IWineD3DDeviceImpl_CreateCubeTexture,
7768 IWineD3DDeviceImpl_CreateQuery,
7769 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7770 IWineD3DDeviceImpl_CreateVertexDeclaration,
7771 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7772 IWineD3DDeviceImpl_CreateVertexShader,
7773 IWineD3DDeviceImpl_CreatePixelShader,
7774 IWineD3DDeviceImpl_CreatePalette,
7775 /*** Odd functions **/
7776 IWineD3DDeviceImpl_Init3D,
7777 IWineD3DDeviceImpl_Uninit3D,
7778 IWineD3DDeviceImpl_SetFullscreen,
7779 IWineD3DDeviceImpl_SetMultithreaded,
7780 IWineD3DDeviceImpl_EvictManagedResources,
7781 IWineD3DDeviceImpl_GetAvailableTextureMem,
7782 IWineD3DDeviceImpl_GetBackBuffer,
7783 IWineD3DDeviceImpl_GetCreationParameters,
7784 IWineD3DDeviceImpl_GetDeviceCaps,
7785 IWineD3DDeviceImpl_GetDirect3D,
7786 IWineD3DDeviceImpl_GetDisplayMode,
7787 IWineD3DDeviceImpl_SetDisplayMode,
7788 IWineD3DDeviceImpl_GetHWND,
7789 IWineD3DDeviceImpl_SetHWND,
7790 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7791 IWineD3DDeviceImpl_GetRasterStatus,
7792 IWineD3DDeviceImpl_GetSwapChain,
7793 IWineD3DDeviceImpl_Reset,
7794 IWineD3DDeviceImpl_SetDialogBoxMode,
7795 IWineD3DDeviceImpl_SetCursorProperties,
7796 IWineD3DDeviceImpl_SetCursorPosition,
7797 IWineD3DDeviceImpl_ShowCursor,
7798 IWineD3DDeviceImpl_TestCooperativeLevel,
7799 /*** Getters and setters **/
7800 IWineD3DDeviceImpl_SetClipPlane,
7801 IWineD3DDeviceImpl_GetClipPlane,
7802 IWineD3DDeviceImpl_SetClipStatus,
7803 IWineD3DDeviceImpl_GetClipStatus,
7804 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7805 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7806 IWineD3DDeviceImpl_SetDepthStencilSurface,
7807 IWineD3DDeviceImpl_GetDepthStencilSurface,
7808 IWineD3DDeviceImpl_SetFVF,
7809 IWineD3DDeviceImpl_GetFVF,
7810 IWineD3DDeviceImpl_SetGammaRamp,
7811 IWineD3DDeviceImpl_GetGammaRamp,
7812 IWineD3DDeviceImpl_SetIndices,
7813 IWineD3DDeviceImpl_GetIndices,
7814 IWineD3DDeviceImpl_SetBaseVertexIndex,
7815 IWineD3DDeviceImpl_GetBaseVertexIndex,
7816 IWineD3DDeviceImpl_SetLight,
7817 IWineD3DDeviceImpl_GetLight,
7818 IWineD3DDeviceImpl_SetLightEnable,
7819 IWineD3DDeviceImpl_GetLightEnable,
7820 IWineD3DDeviceImpl_SetMaterial,
7821 IWineD3DDeviceImpl_GetMaterial,
7822 IWineD3DDeviceImpl_SetNPatchMode,
7823 IWineD3DDeviceImpl_GetNPatchMode,
7824 IWineD3DDeviceImpl_SetPaletteEntries,
7825 IWineD3DDeviceImpl_GetPaletteEntries,
7826 IWineD3DDeviceImpl_SetPixelShader,
7827 IWineD3DDeviceImpl_GetPixelShader,
7828 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7829 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7830 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7831 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7832 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7833 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7834 IWineD3DDeviceImpl_SetRenderState,
7835 IWineD3DDeviceImpl_GetRenderState,
7836 IWineD3DDeviceImpl_SetRenderTarget,
7837 IWineD3DDeviceImpl_GetRenderTarget,
7838 IWineD3DDeviceImpl_SetFrontBackBuffers,
7839 IWineD3DDeviceImpl_SetSamplerState,
7840 IWineD3DDeviceImpl_GetSamplerState,
7841 IWineD3DDeviceImpl_SetScissorRect,
7842 IWineD3DDeviceImpl_GetScissorRect,
7843 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7844 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7845 IWineD3DDeviceImpl_SetStreamSource,
7846 IWineD3DDeviceImpl_GetStreamSource,
7847 IWineD3DDeviceImpl_SetStreamSourceFreq,
7848 IWineD3DDeviceImpl_GetStreamSourceFreq,
7849 IWineD3DDeviceImpl_SetTexture,
7850 IWineD3DDeviceImpl_GetTexture,
7851 IWineD3DDeviceImpl_SetTextureStageState,
7852 IWineD3DDeviceImpl_GetTextureStageState,
7853 IWineD3DDeviceImpl_SetTransform,
7854 IWineD3DDeviceImpl_GetTransform,
7855 IWineD3DDeviceImpl_SetVertexDeclaration,
7856 IWineD3DDeviceImpl_GetVertexDeclaration,
7857 IWineD3DDeviceImpl_SetVertexShader,
7858 IWineD3DDeviceImpl_GetVertexShader,
7859 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7860 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7861 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7862 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7863 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7864 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7865 IWineD3DDeviceImpl_SetViewport,
7866 IWineD3DDeviceImpl_GetViewport,
7867 IWineD3DDeviceImpl_MultiplyTransform,
7868 IWineD3DDeviceImpl_ValidateDevice,
7869 IWineD3DDeviceImpl_ProcessVertices,
7870 /*** State block ***/
7871 IWineD3DDeviceImpl_BeginStateBlock,
7872 IWineD3DDeviceImpl_EndStateBlock,
7873 /*** Scene management ***/
7874 IWineD3DDeviceImpl_BeginScene,
7875 IWineD3DDeviceImpl_EndScene,
7876 IWineD3DDeviceImpl_Present,
7877 IWineD3DDeviceImpl_Clear,
7878 /*** Drawing ***/
7879 IWineD3DDeviceImpl_DrawPrimitive,
7880 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7881 IWineD3DDeviceImpl_DrawPrimitiveUP,
7882 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7883 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7884 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7885 IWineD3DDeviceImpl_DrawRectPatch,
7886 IWineD3DDeviceImpl_DrawTriPatch,
7887 IWineD3DDeviceImpl_DeletePatch,
7888 IWineD3DDeviceImpl_ColorFill,
7889 IWineD3DDeviceImpl_UpdateTexture,
7890 IWineD3DDeviceImpl_UpdateSurface,
7891 IWineD3DDeviceImpl_GetFrontBufferData,
7892 /*** object tracking ***/
7893 IWineD3DDeviceImpl_ResourceReleased,
7894 IWineD3DDeviceImpl_EnumResources
7897 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7898 WINED3DRS_ALPHABLENDENABLE ,
7899 WINED3DRS_ALPHAFUNC ,
7900 WINED3DRS_ALPHAREF ,
7901 WINED3DRS_ALPHATESTENABLE ,
7902 WINED3DRS_BLENDOP ,
7903 WINED3DRS_COLORWRITEENABLE ,
7904 WINED3DRS_DESTBLEND ,
7905 WINED3DRS_DITHERENABLE ,
7906 WINED3DRS_FILLMODE ,
7907 WINED3DRS_FOGDENSITY ,
7908 WINED3DRS_FOGEND ,
7909 WINED3DRS_FOGSTART ,
7910 WINED3DRS_LASTPIXEL ,
7911 WINED3DRS_SHADEMODE ,
7912 WINED3DRS_SRCBLEND ,
7913 WINED3DRS_STENCILENABLE ,
7914 WINED3DRS_STENCILFAIL ,
7915 WINED3DRS_STENCILFUNC ,
7916 WINED3DRS_STENCILMASK ,
7917 WINED3DRS_STENCILPASS ,
7918 WINED3DRS_STENCILREF ,
7919 WINED3DRS_STENCILWRITEMASK ,
7920 WINED3DRS_STENCILZFAIL ,
7921 WINED3DRS_TEXTUREFACTOR ,
7922 WINED3DRS_WRAP0 ,
7923 WINED3DRS_WRAP1 ,
7924 WINED3DRS_WRAP2 ,
7925 WINED3DRS_WRAP3 ,
7926 WINED3DRS_WRAP4 ,
7927 WINED3DRS_WRAP5 ,
7928 WINED3DRS_WRAP6 ,
7929 WINED3DRS_WRAP7 ,
7930 WINED3DRS_ZENABLE ,
7931 WINED3DRS_ZFUNC ,
7932 WINED3DRS_ZWRITEENABLE
7935 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
7936 WINED3DTSS_ADDRESSW ,
7937 WINED3DTSS_ALPHAARG0 ,
7938 WINED3DTSS_ALPHAARG1 ,
7939 WINED3DTSS_ALPHAARG2 ,
7940 WINED3DTSS_ALPHAOP ,
7941 WINED3DTSS_BUMPENVLOFFSET ,
7942 WINED3DTSS_BUMPENVLSCALE ,
7943 WINED3DTSS_BUMPENVMAT00 ,
7944 WINED3DTSS_BUMPENVMAT01 ,
7945 WINED3DTSS_BUMPENVMAT10 ,
7946 WINED3DTSS_BUMPENVMAT11 ,
7947 WINED3DTSS_COLORARG0 ,
7948 WINED3DTSS_COLORARG1 ,
7949 WINED3DTSS_COLORARG2 ,
7950 WINED3DTSS_COLOROP ,
7951 WINED3DTSS_RESULTARG ,
7952 WINED3DTSS_TEXCOORDINDEX ,
7953 WINED3DTSS_TEXTURETRANSFORMFLAGS
7956 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
7957 WINED3DSAMP_ADDRESSU ,
7958 WINED3DSAMP_ADDRESSV ,
7959 WINED3DSAMP_ADDRESSW ,
7960 WINED3DSAMP_BORDERCOLOR ,
7961 WINED3DSAMP_MAGFILTER ,
7962 WINED3DSAMP_MINFILTER ,
7963 WINED3DSAMP_MIPFILTER ,
7964 WINED3DSAMP_MIPMAPLODBIAS ,
7965 WINED3DSAMP_MAXMIPLEVEL ,
7966 WINED3DSAMP_MAXANISOTROPY ,
7967 WINED3DSAMP_SRGBTEXTURE ,
7968 WINED3DSAMP_ELEMENTINDEX
7971 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
7972 WINED3DRS_AMBIENT ,
7973 WINED3DRS_AMBIENTMATERIALSOURCE ,
7974 WINED3DRS_CLIPPING ,
7975 WINED3DRS_CLIPPLANEENABLE ,
7976 WINED3DRS_COLORVERTEX ,
7977 WINED3DRS_DIFFUSEMATERIALSOURCE ,
7978 WINED3DRS_EMISSIVEMATERIALSOURCE ,
7979 WINED3DRS_FOGDENSITY ,
7980 WINED3DRS_FOGEND ,
7981 WINED3DRS_FOGSTART ,
7982 WINED3DRS_FOGTABLEMODE ,
7983 WINED3DRS_FOGVERTEXMODE ,
7984 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
7985 WINED3DRS_LIGHTING ,
7986 WINED3DRS_LOCALVIEWER ,
7987 WINED3DRS_MULTISAMPLEANTIALIAS ,
7988 WINED3DRS_MULTISAMPLEMASK ,
7989 WINED3DRS_NORMALIZENORMALS ,
7990 WINED3DRS_PATCHEDGESTYLE ,
7991 WINED3DRS_POINTSCALE_A ,
7992 WINED3DRS_POINTSCALE_B ,
7993 WINED3DRS_POINTSCALE_C ,
7994 WINED3DRS_POINTSCALEENABLE ,
7995 WINED3DRS_POINTSIZE ,
7996 WINED3DRS_POINTSIZE_MAX ,
7997 WINED3DRS_POINTSIZE_MIN ,
7998 WINED3DRS_POINTSPRITEENABLE ,
7999 WINED3DRS_RANGEFOGENABLE ,
8000 WINED3DRS_SPECULARMATERIALSOURCE ,
8001 WINED3DRS_TWEENFACTOR ,
8002 WINED3DRS_VERTEXBLEND ,
8003 WINED3DRS_CULLMODE ,
8004 WINED3DRS_FOGCOLOR
8007 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8008 WINED3DTSS_TEXCOORDINDEX ,
8009 WINED3DTSS_TEXTURETRANSFORMFLAGS
8012 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8013 WINED3DSAMP_DMAPOFFSET
8016 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8017 DWORD rep = This->StateTable[state].representative;
8018 DWORD idx;
8019 BYTE shift;
8020 UINT i;
8021 WineD3DContext *context;
8023 if(!rep) return;
8024 for(i = 0; i < This->numContexts; i++) {
8025 context = This->contexts[i];
8026 if(isStateDirty(context, rep)) continue;
8028 context->dirtyArray[context->numDirtyEntries++] = rep;
8029 idx = rep >> 5;
8030 shift = rep & 0x1f;
8031 context->isStateDirty[idx] |= (1 << shift);
8035 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8036 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8037 /* The drawable size of a pbuffer render target is the current pbuffer size
8039 *width = dev->pbufferWidth;
8040 *height = dev->pbufferHeight;
8043 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8044 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8046 *width = This->pow2Width;
8047 *height = This->pow2Height;
8050 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8051 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8052 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8053 * current context's drawable, which is the size of the back buffer of the swapchain
8054 * the active context belongs to. The back buffer of the swapchain is stored as the
8055 * surface the context belongs to.
8057 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8058 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;