push d2761731c253bfe9a5961252b22d8cea093833f5
[wine/hacks.git] / dlls / wined3d / device.c
blobe1e01e2af177c7036a7386892892fe9e579d0984
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2007 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 if (This->fbo) {
167 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
169 if (This->src_fbo) {
170 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
172 if (This->dst_fbo) {
173 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
176 /* TODO: Clean up all the surfaces and textures! */
177 /* NOTE: You must release the parent if the object was created via a callback
178 ** ***************************/
180 if (!list_empty(&This->resources)) {
181 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
182 dumpResources(&This->resources);
185 if(This->contexts) ERR("Context array not freed!\n");
186 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
187 This->haveHardwareCursor = FALSE;
189 IWineD3D_Release(This->wineD3D);
190 This->wineD3D = NULL;
191 HeapFree(GetProcessHeap(), 0, This);
192 TRACE("Freed device %p\n", This);
193 This = NULL;
195 return refCount;
198 /**********************************************************
199 * IWineD3DDevice implementation follows
200 **********************************************************/
201 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
202 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
203 *pParent = This->parent;
204 IUnknown_AddRef(This->parent);
205 return WINED3D_OK;
208 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
209 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
210 IUnknown *parent) {
211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
212 IWineD3DVertexBufferImpl *object;
213 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
214 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
215 BOOL conv;
217 if(Size == 0) {
218 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
219 *ppVertexBuffer = NULL;
220 return WINED3DERR_INVALIDCALL;
221 } else if(Pool == WINED3DPOOL_SCRATCH) {
222 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
223 * anyway, SCRATCH vertex buffers aren't usable anywhere
225 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
226 *ppVertexBuffer = NULL;
227 return WINED3DERR_INVALIDCALL;
230 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
232 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
233 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
235 object->fvf = FVF;
237 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
238 * drawStridedFast (half-life 2).
240 * Basically converting the vertices in the buffer is quite expensive, and observations
241 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
242 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
244 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
245 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
246 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
247 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
248 * dx7 apps.
249 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
250 * more. In this call we can convert dx7 buffers too.
252 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
253 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
254 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
255 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
256 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
257 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
258 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
259 } else if(dxVersion <= 7 && conv) {
260 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
261 } else {
262 object->Flags |= VBFLAG_CREATEVBO;
264 return WINED3D_OK;
267 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
268 GLenum error, glUsage;
269 TRACE("Creating VBO for Index Buffer %p\n", object);
271 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
272 * restored on the next draw
274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
276 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
277 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
278 ENTER_GL();
280 while(glGetError());
282 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
283 error = glGetError();
284 if(error != GL_NO_ERROR || object->vbo == 0) {
285 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
286 goto out;
289 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
290 error = glGetError();
291 if(error != GL_NO_ERROR) {
292 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
293 goto out;
296 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
297 * copy no readback will be needed
299 glUsage = GL_STATIC_DRAW_ARB;
300 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
301 error = glGetError();
302 if(error != GL_NO_ERROR) {
303 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
304 goto out;
306 LEAVE_GL();
307 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
308 return;
310 out:
311 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
312 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
313 LEAVE_GL();
314 object->vbo = 0;
317 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
318 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
319 HANDLE *sharedHandle, IUnknown *parent) {
320 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
321 IWineD3DIndexBufferImpl *object;
322 TRACE("(%p) Creating index buffer\n", This);
324 /* Allocate the storage for the device */
325 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
327 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
328 CreateIndexBufferVBO(This, object);
331 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
332 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
333 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
335 return WINED3D_OK;
338 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
341 IWineD3DStateBlockImpl *object;
342 int i, j;
343 HRESULT temp_result;
345 D3DCREATEOBJECTINSTANCE(object, StateBlock)
346 object->blockType = Type;
348 for(i = 0; i < LIGHTMAP_SIZE; i++) {
349 list_init(&object->lightMap[i]);
352 /* Special case - Used during initialization to produce a placeholder stateblock
353 so other functions called can update a state block */
354 if (Type == WINED3DSBT_INIT) {
355 /* Don't bother increasing the reference count otherwise a device will never
356 be freed due to circular dependencies */
357 return WINED3D_OK;
360 temp_result = allocate_shader_constants(object);
361 if (WINED3D_OK != temp_result)
362 return temp_result;
364 /* Otherwise, might as well set the whole state block to the appropriate values */
365 if (This->stateBlock != NULL)
366 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
367 else
368 memset(object->streamFreq, 1, sizeof(object->streamFreq));
370 /* Reset the ref and type after kludging it */
371 object->wineD3DDevice = This;
372 object->ref = 1;
373 object->blockType = Type;
375 TRACE("Updating changed flags appropriate for type %d\n", Type);
377 if (Type == WINED3DSBT_ALL) {
379 TRACE("ALL => Pretend everything has changed\n");
380 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
382 /* Lights are not part of the changed / set structure */
383 for(j = 0; j < LIGHTMAP_SIZE; j++) {
384 struct list *e;
385 LIST_FOR_EACH(e, &object->lightMap[j]) {
386 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
387 light->changed = TRUE;
388 light->enabledChanged = TRUE;
391 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
392 object->contained_render_states[j - 1] = j;
394 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
395 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
396 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
397 object->contained_transform_states[j - 1] = j;
399 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
400 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
401 object->contained_vs_consts_f[j] = j;
403 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
404 for(j = 0; j < MAX_CONST_I; j++) {
405 object->contained_vs_consts_i[j] = j;
407 object->num_contained_vs_consts_i = MAX_CONST_I;
408 for(j = 0; j < MAX_CONST_B; j++) {
409 object->contained_vs_consts_b[j] = j;
411 object->num_contained_vs_consts_b = MAX_CONST_B;
412 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
413 object->contained_ps_consts_f[j] = j;
415 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
416 for(j = 0; j < MAX_CONST_I; j++) {
417 object->contained_ps_consts_i[j] = j;
419 object->num_contained_ps_consts_i = MAX_CONST_I;
420 for(j = 0; j < MAX_CONST_B; j++) {
421 object->contained_ps_consts_b[j] = j;
423 object->num_contained_ps_consts_b = MAX_CONST_B;
424 for(i = 0; i < MAX_TEXTURES; i++) {
425 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
426 object->contained_tss_states[object->num_contained_tss_states].stage = i;
427 object->contained_tss_states[object->num_contained_tss_states].state = j;
428 object->num_contained_tss_states++;
431 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
432 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
433 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
434 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
435 object->num_contained_sampler_states++;
439 for(i = 0; i < MAX_STREAMS; i++) {
440 if(object->streamSource[i]) {
441 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
444 if(object->pIndexData) {
445 IWineD3DIndexBuffer_AddRef(object->pIndexData);
447 if(object->vertexShader) {
448 IWineD3DVertexShader_AddRef(object->vertexShader);
450 if(object->pixelShader) {
451 IWineD3DPixelShader_AddRef(object->pixelShader);
454 } else if (Type == WINED3DSBT_PIXELSTATE) {
456 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
457 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
459 object->changed.pixelShader = TRUE;
461 /* Pixel Shader Constants */
462 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
463 object->contained_ps_consts_f[i] = i;
464 object->changed.pixelShaderConstantsF[i] = TRUE;
466 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
467 for (i = 0; i < MAX_CONST_B; ++i) {
468 object->contained_ps_consts_b[i] = i;
469 object->changed.pixelShaderConstantsB[i] = TRUE;
471 object->num_contained_ps_consts_b = MAX_CONST_B;
472 for (i = 0; i < MAX_CONST_I; ++i) {
473 object->contained_ps_consts_i[i] = i;
474 object->changed.pixelShaderConstantsI[i] = TRUE;
476 object->num_contained_ps_consts_i = MAX_CONST_I;
478 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
479 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
480 object->contained_render_states[i] = SavedPixelStates_R[i];
482 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
483 for (j = 0; j < MAX_TEXTURES; j++) {
484 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
485 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
486 object->contained_tss_states[object->num_contained_tss_states].stage = j;
487 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
488 object->num_contained_tss_states++;
491 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
492 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
493 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
494 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
495 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
496 object->num_contained_sampler_states++;
499 if(object->pixelShader) {
500 IWineD3DPixelShader_AddRef(object->pixelShader);
503 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
504 * on them. This makes releasing the buffer easier
506 for(i = 0; i < MAX_STREAMS; i++) {
507 object->streamSource[i] = NULL;
509 object->pIndexData = NULL;
510 object->vertexShader = NULL;
512 } else if (Type == WINED3DSBT_VERTEXSTATE) {
514 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
515 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
517 object->changed.vertexShader = TRUE;
519 /* Vertex Shader Constants */
520 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
521 object->changed.vertexShaderConstantsF[i] = TRUE;
522 object->contained_vs_consts_f[i] = i;
524 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
525 for (i = 0; i < MAX_CONST_B; ++i) {
526 object->changed.vertexShaderConstantsB[i] = TRUE;
527 object->contained_vs_consts_b[i] = i;
529 object->num_contained_vs_consts_b = MAX_CONST_B;
530 for (i = 0; i < MAX_CONST_I; ++i) {
531 object->changed.vertexShaderConstantsI[i] = TRUE;
532 object->contained_vs_consts_i[i] = i;
534 object->num_contained_vs_consts_i = MAX_CONST_I;
535 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
536 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
537 object->contained_render_states[i] = SavedVertexStates_R[i];
539 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
540 for (j = 0; j < MAX_TEXTURES; j++) {
541 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
542 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
543 object->contained_tss_states[object->num_contained_tss_states].stage = j;
544 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
545 object->num_contained_tss_states++;
548 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
549 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
550 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
551 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
552 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
553 object->num_contained_sampler_states++;
557 for(j = 0; j < LIGHTMAP_SIZE; j++) {
558 struct list *e;
559 LIST_FOR_EACH(e, &object->lightMap[j]) {
560 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
561 light->changed = TRUE;
562 light->enabledChanged = TRUE;
566 for(i = 0; i < MAX_STREAMS; i++) {
567 if(object->streamSource[i]) {
568 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
571 if(object->vertexShader) {
572 IWineD3DVertexShader_AddRef(object->vertexShader);
574 object->pIndexData = NULL;
575 object->pixelShader = NULL;
576 } else {
577 FIXME("Unrecognized state block type %d\n", Type);
580 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
581 return WINED3D_OK;
584 /* ************************************
585 MSDN:
586 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
588 Discard
589 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
591 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
593 ******************************** */
595 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
596 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
597 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
598 unsigned int Size = 1;
599 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, NULL, NULL);
600 TRACE("(%p) Create surface\n",This);
602 /** FIXME: Check ranges on the inputs are valid
603 * MSDN
604 * MultisampleQuality
605 * [in] Quality level. The valid range is between zero and one less than the level
606 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
607 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
608 * values of paired render targets, depth stencil surfaces, and the MultiSample type
609 * must all match.
610 *******************************/
614 * TODO: Discard MSDN
615 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
617 * If this flag is set, the contents of the depth stencil buffer will be
618 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
619 * with a different depth surface.
621 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
622 ***************************/
624 if(MultisampleQuality > 0) {
625 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
626 MultisampleQuality=0;
629 /** FIXME: Check that the format is supported
630 * by the device.
631 *******************************/
633 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
634 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
635 * space!
636 *********************************/
637 if (WINED3DFMT_UNKNOWN == Format) {
638 Size = 0;
639 } else if (Format == WINED3DFMT_DXT1) {
640 /* DXT1 is half byte per pixel */
641 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4)) >> 1;
643 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
644 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
645 Format == WINED3DFMT_ATI2N) {
646 Size = ((max(Width,4) * tableEntry->bpp) * max(Height,4));
647 } else {
648 /* The pitch is a multiple of 4 bytes */
649 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
650 Size *= Height;
653 /** Create and initialise the surface resource **/
654 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
655 /* "Standalone" surface */
656 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
658 object->currentDesc.Width = Width;
659 object->currentDesc.Height = Height;
660 object->currentDesc.MultiSampleType = MultiSample;
661 object->currentDesc.MultiSampleQuality = MultisampleQuality;
662 object->glDescription.level = Level;
663 list_init(&object->overlays);
665 /* Flags */
666 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
667 object->Flags |= Discard ? SFLAG_DISCARD : 0;
668 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
669 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
672 if (WINED3DFMT_UNKNOWN != Format) {
673 object->bytesPerPixel = tableEntry->bpp;
674 } else {
675 object->bytesPerPixel = 0;
678 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
680 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
682 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
683 * this function is too deep to need to care about things like this.
684 * Levels need to be checked too, and possibly Type since they all affect what can be done.
685 * ****************************************/
686 switch(Pool) {
687 case WINED3DPOOL_SCRATCH:
688 if(!Lockable)
689 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
690 "which are mutually exclusive, setting lockable to TRUE\n");
691 Lockable = TRUE;
692 break;
693 case WINED3DPOOL_SYSTEMMEM:
694 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
695 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
696 case WINED3DPOOL_MANAGED:
697 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
698 "Usage of DYNAMIC which are mutually exclusive, not doing "
699 "anything just telling you.\n");
700 break;
701 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
702 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
703 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
704 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
705 break;
706 default:
707 FIXME("(%p) Unknown pool %d\n", This, Pool);
708 break;
711 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
712 FIXME("Trying to create a render target that isn't in the default pool\n");
715 /* mark the texture as dirty so that it gets loaded first time around*/
716 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
717 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
718 This, Width, Height, Format, debug_d3dformat(Format),
719 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
721 /* Look at the implementation and set the correct Vtable */
722 switch(Impl) {
723 case SURFACE_OPENGL:
724 /* Check if a 3D adapter is available when creating gl surfaces */
725 if(!This->adapter) {
726 ERR("OpenGL surfaces are not available without opengl\n");
727 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
728 HeapFree(GetProcessHeap(), 0, object);
729 return WINED3DERR_NOTAVAILABLE;
731 break;
733 case SURFACE_GDI:
734 object->lpVtbl = &IWineGDISurface_Vtbl;
735 break;
737 default:
738 /* To be sure to catch this */
739 ERR("Unknown requested surface implementation %d!\n", Impl);
740 IWineD3DSurface_Release((IWineD3DSurface *) object);
741 return WINED3DERR_INVALIDCALL;
744 list_init(&object->renderbuffers);
746 /* Call the private setup routine */
747 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
751 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
752 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
753 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
754 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
756 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
757 IWineD3DTextureImpl *object;
758 unsigned int i;
759 UINT tmpW;
760 UINT tmpH;
761 HRESULT hr;
762 unsigned int pow2Width;
763 unsigned int pow2Height;
764 const GlPixelFormatDesc *glDesc;
765 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
767 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
768 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
769 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
771 /* TODO: It should only be possible to create textures for formats
772 that are reported as supported */
773 if (WINED3DFMT_UNKNOWN >= Format) {
774 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
775 return WINED3DERR_INVALIDCALL;
778 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
779 D3DINITIALIZEBASETEXTURE(object->baseTexture);
780 object->width = Width;
781 object->height = Height;
783 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
784 object->baseTexture.minMipLookup = &minMipLookup;
785 object->baseTexture.magLookup = &magLookup;
786 } else {
787 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
788 object->baseTexture.magLookup = &magLookup_noFilter;
791 /** Non-power2 support **/
792 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
793 pow2Width = Width;
794 pow2Height = Height;
795 } else {
796 /* Find the nearest pow2 match */
797 pow2Width = pow2Height = 1;
798 while (pow2Width < Width) pow2Width <<= 1;
799 while (pow2Height < Height) pow2Height <<= 1;
801 if(pow2Width != Width || pow2Height != Height) {
802 if(Levels > 1) {
803 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
804 HeapFree(GetProcessHeap(), 0, object);
805 *ppTexture = NULL;
806 return WINED3DERR_INVALIDCALL;
807 } else {
808 Levels = 1;
813 /** FIXME: add support for real non-power-two if it's provided by the video card **/
814 /* Precalculated scaling for 'faked' non power of two texture coords.
815 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
816 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
817 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
819 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
820 object->baseTexture.pow2Matrix[0] = 1.0;
821 object->baseTexture.pow2Matrix[5] = 1.0;
822 object->baseTexture.pow2Matrix[10] = 1.0;
823 object->baseTexture.pow2Matrix[15] = 1.0;
824 object->target = GL_TEXTURE_2D;
825 object->cond_np2 = TRUE;
826 pow2Width = Width;
827 pow2Height = Height;
828 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
829 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
830 (Width != pow2Width || Height != pow2Height) &&
831 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
833 object->baseTexture.pow2Matrix[0] = (float)Width;
834 object->baseTexture.pow2Matrix[5] = (float)Height;
835 object->baseTexture.pow2Matrix[10] = 1.0;
836 object->baseTexture.pow2Matrix[15] = 1.0;
837 object->target = GL_TEXTURE_RECTANGLE_ARB;
838 object->cond_np2 = TRUE;
839 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
840 } else {
841 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
842 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
843 object->baseTexture.pow2Matrix[10] = 1.0;
844 object->baseTexture.pow2Matrix[15] = 1.0;
845 object->target = GL_TEXTURE_2D;
846 object->cond_np2 = FALSE;
848 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
850 /* Calculate levels for mip mapping */
851 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
852 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
853 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
854 return WINED3DERR_INVALIDCALL;
856 if(Levels > 1) {
857 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
858 return WINED3DERR_INVALIDCALL;
860 object->baseTexture.levels = 1;
861 } else if (Levels == 0) {
862 TRACE("calculating levels %d\n", object->baseTexture.levels);
863 object->baseTexture.levels++;
864 tmpW = Width;
865 tmpH = Height;
866 while (tmpW > 1 || tmpH > 1) {
867 tmpW = max(1, tmpW >> 1);
868 tmpH = max(1, tmpH >> 1);
869 object->baseTexture.levels++;
871 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
874 /* Generate all the surfaces */
875 tmpW = Width;
876 tmpH = Height;
877 for (i = 0; i < object->baseTexture.levels; i++)
879 /* use the callback to create the texture surface */
880 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
881 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
882 FIXME("Failed to create surface %p\n", object);
883 /* clean up */
884 object->surfaces[i] = NULL;
885 IWineD3DTexture_Release((IWineD3DTexture *)object);
887 *ppTexture = NULL;
888 return hr;
891 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
892 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
893 /* calculate the next mipmap level */
894 tmpW = max(1, tmpW >> 1);
895 tmpH = max(1, tmpH >> 1);
897 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
899 TRACE("(%p) : Created texture %p\n", This, object);
900 return WINED3D_OK;
903 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
904 UINT Width, UINT Height, UINT Depth,
905 UINT Levels, DWORD Usage,
906 WINED3DFORMAT Format, WINED3DPOOL Pool,
907 IWineD3DVolumeTexture **ppVolumeTexture,
908 HANDLE *pSharedHandle, IUnknown *parent,
909 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
911 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
912 IWineD3DVolumeTextureImpl *object;
913 unsigned int i;
914 UINT tmpW;
915 UINT tmpH;
916 UINT tmpD;
917 const GlPixelFormatDesc *glDesc;
919 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
921 /* TODO: It should only be possible to create textures for formats
922 that are reported as supported */
923 if (WINED3DFMT_UNKNOWN >= Format) {
924 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
925 return WINED3DERR_INVALIDCALL;
927 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
928 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
929 return WINED3DERR_INVALIDCALL;
932 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
933 D3DINITIALIZEBASETEXTURE(object->baseTexture);
935 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
936 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
938 object->width = Width;
939 object->height = Height;
940 object->depth = Depth;
942 /* Is NP2 support for volumes needed? */
943 object->baseTexture.pow2Matrix[ 0] = 1.0;
944 object->baseTexture.pow2Matrix[ 5] = 1.0;
945 object->baseTexture.pow2Matrix[10] = 1.0;
946 object->baseTexture.pow2Matrix[15] = 1.0;
948 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
949 object->baseTexture.minMipLookup = &minMipLookup;
950 object->baseTexture.magLookup = &magLookup;
951 } else {
952 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
953 object->baseTexture.magLookup = &magLookup_noFilter;
956 /* Calculate levels for mip mapping */
957 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
958 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
959 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
960 return WINED3DERR_INVALIDCALL;
962 if(Levels > 1) {
963 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
964 return WINED3DERR_INVALIDCALL;
966 Levels = 1;
967 } else if (Levels == 0) {
968 object->baseTexture.levels++;
969 tmpW = Width;
970 tmpH = Height;
971 tmpD = Depth;
972 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
973 tmpW = max(1, tmpW >> 1);
974 tmpH = max(1, tmpH >> 1);
975 tmpD = max(1, tmpD >> 1);
976 object->baseTexture.levels++;
978 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
981 /* Generate all the surfaces */
982 tmpW = Width;
983 tmpH = Height;
984 tmpD = Depth;
986 for (i = 0; i < object->baseTexture.levels; i++)
988 HRESULT hr;
989 /* Create the volume */
990 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
991 &object->volumes[i], pSharedHandle);
993 if(FAILED(hr)) {
994 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
995 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
996 *ppVolumeTexture = NULL;
997 return hr;
1000 /* Set its container to this object */
1001 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1003 /* calculate the next mipmap level */
1004 tmpW = max(1, tmpW >> 1);
1005 tmpH = max(1, tmpH >> 1);
1006 tmpD = max(1, tmpD >> 1);
1008 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1010 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1011 TRACE("(%p) : Created volume texture %p\n", This, object);
1012 return WINED3D_OK;
1015 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1016 UINT Width, UINT Height, UINT Depth,
1017 DWORD Usage,
1018 WINED3DFORMAT Format, WINED3DPOOL Pool,
1019 IWineD3DVolume** ppVolume,
1020 HANDLE* pSharedHandle, IUnknown *parent) {
1022 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1023 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1024 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1026 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1027 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1028 return WINED3DERR_INVALIDCALL;
1031 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1033 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1034 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1036 object->currentDesc.Width = Width;
1037 object->currentDesc.Height = Height;
1038 object->currentDesc.Depth = Depth;
1039 object->bytesPerPixel = formatDesc->bpp;
1041 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1042 object->lockable = TRUE;
1043 object->locked = FALSE;
1044 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1045 object->dirty = TRUE;
1047 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1050 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1051 UINT Levels, DWORD Usage,
1052 WINED3DFORMAT Format, WINED3DPOOL Pool,
1053 IWineD3DCubeTexture **ppCubeTexture,
1054 HANDLE *pSharedHandle, IUnknown *parent,
1055 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1058 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1059 unsigned int i, j;
1060 UINT tmpW;
1061 HRESULT hr;
1062 unsigned int pow2EdgeLength = EdgeLength;
1063 const GlPixelFormatDesc *glDesc;
1064 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1066 /* TODO: It should only be possible to create textures for formats
1067 that are reported as supported */
1068 if (WINED3DFMT_UNKNOWN >= Format) {
1069 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1070 return WINED3DERR_INVALIDCALL;
1073 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1074 WARN("(%p) : Tried to create not supported cube texture\n", This);
1075 return WINED3DERR_INVALIDCALL;
1078 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1079 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1081 TRACE("(%p) Create Cube Texture\n", This);
1083 /** Non-power2 support **/
1085 /* Find the nearest pow2 match */
1086 pow2EdgeLength = 1;
1087 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1089 object->edgeLength = EdgeLength;
1090 /* TODO: support for native non-power 2 */
1091 /* Precalculated scaling for 'faked' non power of two texture coords */
1092 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1093 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1094 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1095 object->baseTexture.pow2Matrix[15] = 1.0;
1097 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1098 object->baseTexture.minMipLookup = &minMipLookup;
1099 object->baseTexture.magLookup = &magLookup;
1100 } else {
1101 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1102 object->baseTexture.magLookup = &magLookup_noFilter;
1105 /* Calculate levels for mip mapping */
1106 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1107 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1108 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1109 HeapFree(GetProcessHeap(), 0, object);
1110 *ppCubeTexture = NULL;
1112 return WINED3DERR_INVALIDCALL;
1114 if(Levels > 1) {
1115 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1116 HeapFree(GetProcessHeap(), 0, object);
1117 *ppCubeTexture = NULL;
1119 return WINED3DERR_INVALIDCALL;
1121 Levels = 1;
1122 } else if (Levels == 0) {
1123 object->baseTexture.levels++;
1124 tmpW = EdgeLength;
1125 while (tmpW > 1) {
1126 tmpW = max(1, tmpW >> 1);
1127 object->baseTexture.levels++;
1129 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1132 /* Generate all the surfaces */
1133 tmpW = EdgeLength;
1134 for (i = 0; i < object->baseTexture.levels; i++) {
1136 /* Create the 6 faces */
1137 for (j = 0; j < 6; j++) {
1139 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1140 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1142 if(hr!= WINED3D_OK) {
1143 /* clean up */
1144 int k;
1145 int l;
1146 for (l = 0; l < j; l++) {
1147 IWineD3DSurface_Release(object->surfaces[l][i]);
1149 for (k = 0; k < i; k++) {
1150 for (l = 0; l < 6; l++) {
1151 IWineD3DSurface_Release(object->surfaces[l][k]);
1155 FIXME("(%p) Failed to create surface\n",object);
1156 HeapFree(GetProcessHeap(),0,object);
1157 *ppCubeTexture = NULL;
1158 return hr;
1160 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1161 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1163 tmpW = max(1, tmpW >> 1);
1165 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1167 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1168 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1169 return WINED3D_OK;
1172 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1174 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1175 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1176 const IWineD3DQueryVtbl *vtable;
1178 /* Just a check to see if we support this type of query */
1179 switch(Type) {
1180 case WINED3DQUERYTYPE_OCCLUSION:
1181 TRACE("(%p) occlusion query\n", This);
1182 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1183 hr = WINED3D_OK;
1184 else
1185 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1187 vtable = &IWineD3DOcclusionQuery_Vtbl;
1188 break;
1190 case WINED3DQUERYTYPE_EVENT:
1191 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1192 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1193 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1195 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1197 vtable = &IWineD3DEventQuery_Vtbl;
1198 hr = WINED3D_OK;
1199 break;
1201 case WINED3DQUERYTYPE_VCACHE:
1202 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1203 case WINED3DQUERYTYPE_VERTEXSTATS:
1204 case WINED3DQUERYTYPE_TIMESTAMP:
1205 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1206 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1207 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1208 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1209 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1210 case WINED3DQUERYTYPE_PIXELTIMINGS:
1211 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1212 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1213 default:
1214 /* Use the base Query vtable until we have a special one for each query */
1215 vtable = &IWineD3DQuery_Vtbl;
1216 FIXME("(%p) Unhandled query type %d\n", This, Type);
1218 if(NULL == ppQuery || hr != WINED3D_OK) {
1219 return hr;
1222 D3DCREATEOBJECTINSTANCE(object, Query)
1223 object->lpVtbl = vtable;
1224 object->type = Type;
1225 object->state = QUERY_CREATED;
1226 /* allocated the 'extended' data based on the type of query requested */
1227 switch(Type){
1228 case WINED3DQUERYTYPE_OCCLUSION:
1229 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1230 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1232 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1233 TRACE("(%p) Allocating data for an occlusion query\n", This);
1234 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1235 break;
1237 case WINED3DQUERYTYPE_EVENT:
1238 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1239 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1241 if(GL_SUPPORT(APPLE_FENCE)) {
1242 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1243 checkGLcall("glGenFencesAPPLE");
1244 } else if(GL_SUPPORT(NV_FENCE)) {
1245 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1246 checkGLcall("glGenFencesNV");
1248 break;
1250 case WINED3DQUERYTYPE_VCACHE:
1251 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1252 case WINED3DQUERYTYPE_VERTEXSTATS:
1253 case WINED3DQUERYTYPE_TIMESTAMP:
1254 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1255 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1256 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1257 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1258 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1259 case WINED3DQUERYTYPE_PIXELTIMINGS:
1260 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1261 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1262 default:
1263 object->extendedData = 0;
1264 FIXME("(%p) Unhandled query type %d\n",This , Type);
1266 TRACE("(%p) : Created Query %p\n", This, object);
1267 return WINED3D_OK;
1270 /*****************************************************************************
1271 * IWineD3DDeviceImpl_SetupFullscreenWindow
1273 * Helper function that modifies a HWND's Style and ExStyle for proper
1274 * fullscreen use.
1276 * Params:
1277 * iface: Pointer to the IWineD3DDevice interface
1278 * window: Window to setup
1280 *****************************************************************************/
1281 static LONG fullscreen_style(LONG orig_style) {
1282 LONG style = orig_style;
1283 style &= ~WS_CAPTION;
1284 style &= ~WS_THICKFRAME;
1286 /* Make sure the window is managed, otherwise we won't get keyboard input */
1287 style |= WS_POPUP | WS_SYSMENU;
1289 return style;
1292 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1293 LONG exStyle = orig_exStyle;
1295 /* Filter out window decorations */
1296 exStyle &= ~WS_EX_WINDOWEDGE;
1297 exStyle &= ~WS_EX_CLIENTEDGE;
1299 return exStyle;
1302 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1305 LONG style, exStyle;
1306 /* Don't do anything if an original style is stored.
1307 * That shouldn't happen
1309 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1310 if (This->style || This->exStyle) {
1311 ERR("(%p): Want to change the window parameters of HWND %p, but "
1312 "another style is stored for restoration afterwards\n", This, window);
1315 /* Get the parameters and save them */
1316 style = GetWindowLongW(window, GWL_STYLE);
1317 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1318 This->style = style;
1319 This->exStyle = exStyle;
1321 style = fullscreen_style(style);
1322 exStyle = fullscreen_exStyle(exStyle);
1324 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1325 This->style, This->exStyle, style, exStyle);
1327 SetWindowLongW(window, GWL_STYLE, style);
1328 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1330 /* Inform the window about the update. */
1331 SetWindowPos(window, HWND_TOP, 0, 0,
1332 w, h, SWP_FRAMECHANGED);
1333 ShowWindow(window, SW_NORMAL);
1336 /*****************************************************************************
1337 * IWineD3DDeviceImpl_RestoreWindow
1339 * Helper function that restores a windows' properties when taking it out
1340 * of fullscreen mode
1342 * Params:
1343 * iface: Pointer to the IWineD3DDevice interface
1344 * window: Window to setup
1346 *****************************************************************************/
1347 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1348 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1349 LONG style, exStyle;
1351 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1352 * switch, do nothing
1354 if (!This->style && !This->exStyle) return;
1356 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1357 This, window, This->style, This->exStyle);
1359 style = GetWindowLongW(window, GWL_STYLE);
1360 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1362 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1363 * Some applications change it before calling Reset() when switching between windowed and
1364 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1366 if(style == fullscreen_style(This->style) &&
1367 exStyle == fullscreen_style(This->exStyle)) {
1368 SetWindowLongW(window, GWL_STYLE, This->style);
1369 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1372 /* Delete the old values */
1373 This->style = 0;
1374 This->exStyle = 0;
1376 /* Inform the window about the update */
1377 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1378 0, 0, 0, 0, /* Pos, Size, ignored */
1379 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1382 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1383 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1384 IUnknown* parent,
1385 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1386 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1387 WINED3DSURFTYPE surface_type) {
1388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1390 HDC hDc;
1391 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1392 HRESULT hr = WINED3D_OK;
1393 IUnknown *bufferParent;
1394 BOOL displaymode_set = FALSE;
1395 WINED3DDISPLAYMODE Mode;
1396 const StaticPixelFormatDesc *formatDesc;
1398 TRACE("(%p) : Created Additional Swap Chain\n", This);
1400 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1401 * does a device hold a reference to a swap chain giving them a lifetime of the device
1402 * or does the swap chain notify the device of its destruction.
1403 *******************************/
1405 /* Check the params */
1406 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1407 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1408 return WINED3DERR_INVALIDCALL;
1409 } else if (pPresentationParameters->BackBufferCount > 1) {
1410 FIXME("The app requests more than one back buffer, this can't be supported properly. Please configure the application to use double buffering(=1 back buffer) if possible\n");
1413 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1414 switch(surface_type) {
1415 case SURFACE_GDI:
1416 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1417 break;
1418 case SURFACE_OPENGL:
1419 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1420 break;
1421 case SURFACE_UNKNOWN:
1422 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1423 return WINED3DERR_INVALIDCALL;
1426 /*********************
1427 * Lookup the window Handle and the relating X window handle
1428 ********************/
1430 /* Setup hwnd we are using, plus which display this equates to */
1431 object->win_handle = pPresentationParameters->hDeviceWindow;
1432 if (!object->win_handle) {
1433 object->win_handle = This->createParms.hFocusWindow;
1435 if(!pPresentationParameters->Windowed && object->win_handle) {
1436 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1437 pPresentationParameters->BackBufferWidth,
1438 pPresentationParameters->BackBufferHeight);
1441 hDc = GetDC(object->win_handle);
1442 TRACE("Using hDc %p\n", hDc);
1444 if (NULL == hDc) {
1445 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1446 return WINED3DERR_NOTAVAILABLE;
1449 /* Get info on the current display setup */
1450 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1451 object->orig_width = Mode.Width;
1452 object->orig_height = Mode.Height;
1453 object->orig_fmt = Mode.Format;
1454 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1456 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1457 * then the corresponding dimension of the client area of the hDeviceWindow
1458 * (or the focus window, if hDeviceWindow is NULL) is taken.
1459 **********************/
1461 if (pPresentationParameters->Windowed &&
1462 ((pPresentationParameters->BackBufferWidth == 0) ||
1463 (pPresentationParameters->BackBufferHeight == 0) ||
1464 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1466 RECT Rect;
1467 GetClientRect(object->win_handle, &Rect);
1469 if (pPresentationParameters->BackBufferWidth == 0) {
1470 pPresentationParameters->BackBufferWidth = Rect.right;
1471 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1473 if (pPresentationParameters->BackBufferHeight == 0) {
1474 pPresentationParameters->BackBufferHeight = Rect.bottom;
1475 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1477 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1478 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1479 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1483 /* Put the correct figures in the presentation parameters */
1484 TRACE("Copying across presentation parameters\n");
1485 object->presentParms = *pPresentationParameters;
1487 TRACE("calling rendertarget CB\n");
1488 hr = D3DCB_CreateRenderTarget(This->parent,
1489 parent,
1490 object->presentParms.BackBufferWidth,
1491 object->presentParms.BackBufferHeight,
1492 object->presentParms.BackBufferFormat,
1493 object->presentParms.MultiSampleType,
1494 object->presentParms.MultiSampleQuality,
1495 TRUE /* Lockable */,
1496 &object->frontBuffer,
1497 NULL /* pShared (always null)*/);
1498 if (object->frontBuffer != NULL) {
1499 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1500 if(surface_type == SURFACE_OPENGL) {
1501 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1503 } else {
1504 ERR("Failed to create the front buffer\n");
1505 goto error;
1508 /*********************
1509 * Windowed / Fullscreen
1510 *******************/
1513 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1514 * so we should really check to see if there is a fullscreen swapchain already
1515 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1516 **************************************/
1518 if (!pPresentationParameters->Windowed) {
1519 WINED3DDISPLAYMODE mode;
1522 /* Change the display settings */
1523 mode.Width = pPresentationParameters->BackBufferWidth;
1524 mode.Height = pPresentationParameters->BackBufferHeight;
1525 mode.Format = pPresentationParameters->BackBufferFormat;
1526 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1528 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1529 displaymode_set = TRUE;
1533 * Create an opengl context for the display visual
1534 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1535 * use different properties after that point in time. FIXME: How to handle when requested format
1536 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1537 * it chooses is identical to the one already being used!
1538 **********************************/
1539 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1541 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1542 if(!object->context)
1543 return E_OUTOFMEMORY;
1544 object->num_contexts = 1;
1546 if(surface_type == SURFACE_OPENGL) {
1547 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1548 if (!object->context[0]) {
1549 ERR("Failed to create a new context\n");
1550 hr = WINED3DERR_NOTAVAILABLE;
1551 goto error;
1552 } else {
1553 TRACE("Context created (HWND=%p, glContext=%p)\n",
1554 object->win_handle, object->context[0]->glCtx);
1558 /*********************
1559 * Create the back, front and stencil buffers
1560 *******************/
1561 if(object->presentParms.BackBufferCount > 0) {
1562 int i;
1564 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1565 if(!object->backBuffer) {
1566 ERR("Out of memory\n");
1567 hr = E_OUTOFMEMORY;
1568 goto error;
1571 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1572 TRACE("calling rendertarget CB\n");
1573 hr = D3DCB_CreateRenderTarget(This->parent,
1574 parent,
1575 object->presentParms.BackBufferWidth,
1576 object->presentParms.BackBufferHeight,
1577 object->presentParms.BackBufferFormat,
1578 object->presentParms.MultiSampleType,
1579 object->presentParms.MultiSampleQuality,
1580 TRUE /* Lockable */,
1581 &object->backBuffer[i],
1582 NULL /* pShared (always null)*/);
1583 if(hr == WINED3D_OK && object->backBuffer[i]) {
1584 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1585 } else {
1586 ERR("Cannot create new back buffer\n");
1587 goto error;
1589 if(surface_type == SURFACE_OPENGL) {
1590 ENTER_GL();
1591 glDrawBuffer(GL_BACK);
1592 checkGLcall("glDrawBuffer(GL_BACK)");
1593 LEAVE_GL();
1596 } else {
1597 object->backBuffer = NULL;
1599 /* Single buffering - draw to front buffer */
1600 if(surface_type == SURFACE_OPENGL) {
1601 ENTER_GL();
1602 glDrawBuffer(GL_FRONT);
1603 checkGLcall("glDrawBuffer(GL_FRONT)");
1604 LEAVE_GL();
1608 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1609 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1610 TRACE("Creating depth stencil buffer\n");
1611 if (This->auto_depth_stencil_buffer == NULL ) {
1612 hr = D3DCB_CreateDepthStencil(This->parent,
1613 parent,
1614 object->presentParms.BackBufferWidth,
1615 object->presentParms.BackBufferHeight,
1616 object->presentParms.AutoDepthStencilFormat,
1617 object->presentParms.MultiSampleType,
1618 object->presentParms.MultiSampleQuality,
1619 FALSE /* FIXME: Discard */,
1620 &This->auto_depth_stencil_buffer,
1621 NULL /* pShared (always null)*/ );
1622 if (This->auto_depth_stencil_buffer != NULL)
1623 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1626 /** TODO: A check on width, height and multisample types
1627 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1628 ****************************/
1629 object->wantsDepthStencilBuffer = TRUE;
1630 } else {
1631 object->wantsDepthStencilBuffer = FALSE;
1634 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1636 TRACE("Created swapchain %p\n", object);
1637 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1638 return WINED3D_OK;
1640 error:
1641 if (displaymode_set) {
1642 DEVMODEW devmode;
1643 RECT clip_rc;
1645 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1646 ClipCursor(NULL);
1648 /* Change the display settings */
1649 memset(&devmode, 0, sizeof(devmode));
1650 devmode.dmSize = sizeof(devmode);
1651 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1652 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1653 devmode.dmPelsWidth = object->orig_width;
1654 devmode.dmPelsHeight = object->orig_height;
1655 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1658 if (object->backBuffer) {
1659 int i;
1660 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1661 if(object->backBuffer[i]) {
1662 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1663 IUnknown_Release(bufferParent); /* once for the get parent */
1664 if (IUnknown_Release(bufferParent) > 0) {
1665 FIXME("(%p) Something's still holding the back buffer\n",This);
1669 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1670 object->backBuffer = NULL;
1672 if(object->context[0])
1673 DestroyContext(This, object->context[0]);
1674 if(object->frontBuffer) {
1675 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1676 IUnknown_Release(bufferParent); /* once for the get parent */
1677 if (IUnknown_Release(bufferParent) > 0) {
1678 FIXME("(%p) Something's still holding the front buffer\n",This);
1681 HeapFree(GetProcessHeap(), 0, object);
1682 return hr;
1685 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1686 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1687 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1688 TRACE("(%p)\n", This);
1690 return This->NumberOfSwapChains;
1693 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1694 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1695 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1697 if(iSwapChain < This->NumberOfSwapChains) {
1698 *pSwapChain = This->swapchains[iSwapChain];
1699 IWineD3DSwapChain_AddRef(*pSwapChain);
1700 TRACE("(%p) returning %p\n", This, *pSwapChain);
1701 return WINED3D_OK;
1702 } else {
1703 TRACE("Swapchain out of range\n");
1704 *pSwapChain = NULL;
1705 return WINED3DERR_INVALIDCALL;
1709 /*****
1710 * Vertex Declaration
1711 *****/
1712 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1713 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1714 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1715 IWineD3DVertexDeclarationImpl *object = NULL;
1716 HRESULT hr = WINED3D_OK;
1718 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1719 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1721 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1723 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1724 if(FAILED(hr)) {
1725 *ppVertexDeclaration = NULL;
1726 HeapFree(GetProcessHeap(), 0, object);
1729 return hr;
1732 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1733 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1735 unsigned int idx, idx2;
1736 unsigned int offset;
1737 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1738 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1739 BOOL has_blend_idx = has_blend &&
1740 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1741 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1742 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1743 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1744 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1745 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1746 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1748 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1749 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1751 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1752 WINED3DVERTEXELEMENT *elements = NULL;
1754 unsigned int size;
1755 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1756 if (has_blend_idx) num_blends--;
1758 /* Compute declaration size */
1759 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1760 has_psize + has_diffuse + has_specular + num_textures + 1;
1762 /* convert the declaration */
1763 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1764 if (!elements)
1765 return 0;
1767 elements[size-1] = end_element;
1768 idx = 0;
1769 if (has_pos) {
1770 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1772 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1774 else {
1775 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1776 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1778 elements[idx].UsageIndex = 0;
1779 idx++;
1781 if (has_blend && (num_blends > 0)) {
1782 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1783 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1784 else
1785 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1786 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1787 elements[idx].UsageIndex = 0;
1788 idx++;
1790 if (has_blend_idx) {
1791 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1792 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1793 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1794 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1795 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1796 else
1797 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1798 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1799 elements[idx].UsageIndex = 0;
1800 idx++;
1802 if (has_normal) {
1803 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1804 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1805 elements[idx].UsageIndex = 0;
1806 idx++;
1808 if (has_psize) {
1809 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1810 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1811 elements[idx].UsageIndex = 0;
1812 idx++;
1814 if (has_diffuse) {
1815 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1816 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1817 elements[idx].UsageIndex = 0;
1818 idx++;
1820 if (has_specular) {
1821 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1822 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1823 elements[idx].UsageIndex = 1;
1824 idx++;
1826 for (idx2 = 0; idx2 < num_textures; idx2++) {
1827 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1828 switch (numcoords) {
1829 case WINED3DFVF_TEXTUREFORMAT1:
1830 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1831 break;
1832 case WINED3DFVF_TEXTUREFORMAT2:
1833 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1834 break;
1835 case WINED3DFVF_TEXTUREFORMAT3:
1836 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1837 break;
1838 case WINED3DFVF_TEXTUREFORMAT4:
1839 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1840 break;
1842 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1843 elements[idx].UsageIndex = idx2;
1844 idx++;
1847 /* Now compute offsets, and initialize the rest of the fields */
1848 for (idx = 0, offset = 0; idx < size-1; idx++) {
1849 elements[idx].Stream = 0;
1850 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1851 elements[idx].Offset = offset;
1852 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1855 *ppVertexElements = elements;
1856 return size;
1859 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1860 WINED3DVERTEXELEMENT* elements = NULL;
1861 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1862 unsigned int size;
1863 DWORD hr;
1865 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1866 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1868 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1869 HeapFree(GetProcessHeap(), 0, elements);
1870 if (hr != S_OK) return hr;
1872 return WINED3D_OK;
1875 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1877 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1878 HRESULT hr = WINED3D_OK;
1879 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1880 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1882 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1884 if (vertex_declaration) {
1885 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1888 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1890 if (WINED3D_OK != hr) {
1891 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1892 IWineD3DVertexShader_Release(*ppVertexShader);
1893 return WINED3DERR_INVALIDCALL;
1895 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1897 return WINED3D_OK;
1900 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1901 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1902 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1903 HRESULT hr = WINED3D_OK;
1905 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1906 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1907 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1908 if (WINED3D_OK == hr) {
1909 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1910 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1911 } else {
1912 WARN("(%p) : Failed to create pixel shader\n", This);
1915 return hr;
1918 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1919 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1920 IWineD3DPaletteImpl *object;
1921 HRESULT hr;
1922 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1924 /* Create the new object */
1925 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1926 if(!object) {
1927 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1928 return E_OUTOFMEMORY;
1931 object->lpVtbl = &IWineD3DPalette_Vtbl;
1932 object->ref = 1;
1933 object->Flags = Flags;
1934 object->parent = Parent;
1935 object->wineD3DDevice = This;
1936 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1938 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1940 if(!object->hpal) {
1941 HeapFree( GetProcessHeap(), 0, object);
1942 return E_OUTOFMEMORY;
1945 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1946 if(FAILED(hr)) {
1947 IWineD3DPalette_Release((IWineD3DPalette *) object);
1948 return hr;
1951 *Palette = (IWineD3DPalette *) object;
1953 return WINED3D_OK;
1956 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1957 HBITMAP hbm;
1958 BITMAP bm;
1959 HRESULT hr;
1960 HDC dcb = NULL, dcs = NULL;
1961 WINEDDCOLORKEY colorkey;
1963 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1964 if(hbm)
1966 GetObjectA(hbm, sizeof(BITMAP), &bm);
1967 dcb = CreateCompatibleDC(NULL);
1968 if(!dcb) goto out;
1969 SelectObject(dcb, hbm);
1971 else
1973 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1974 * couldn't be loaded
1976 memset(&bm, 0, sizeof(bm));
1977 bm.bmWidth = 32;
1978 bm.bmHeight = 32;
1981 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1982 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1983 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1984 if(FAILED(hr)) {
1985 ERR("Wine logo requested, but failed to create surface\n");
1986 goto out;
1989 if(dcb) {
1990 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1991 if(FAILED(hr)) goto out;
1992 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1993 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1995 colorkey.dwColorSpaceLowValue = 0;
1996 colorkey.dwColorSpaceHighValue = 0;
1997 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1998 } else {
1999 /* Fill the surface with a white color to show that wined3d is there */
2000 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2003 out:
2004 if(dcb) {
2005 DeleteDC(dcb);
2007 if(hbm) {
2008 DeleteObject(hbm);
2010 return;
2013 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2014 unsigned int i;
2015 /* Under DirectX you can have texture stage operations even if no texture is
2016 bound, whereas opengl will only do texture operations when a valid texture is
2017 bound. We emulate this by creating dummy textures and binding them to each
2018 texture stage, but disable all stages by default. Hence if a stage is enabled
2019 then the default texture will kick in until replaced by a SetTexture call */
2020 ENTER_GL();
2022 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2023 /* The dummy texture does not have client storage backing */
2024 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2025 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2027 for (i = 0; i < GL_LIMITS(textures); i++) {
2028 GLubyte white = 255;
2030 /* Make appropriate texture active */
2031 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2032 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2033 checkGLcall("glActiveTextureARB");
2034 } else if (i > 0) {
2035 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2038 /* Generate an opengl texture name */
2039 glGenTextures(1, &This->dummyTextureName[i]);
2040 checkGLcall("glGenTextures");
2041 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2043 /* Generate a dummy 2d texture (not using 1d because they cause many
2044 * DRI drivers fall back to sw) */
2045 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2046 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2047 checkGLcall("glBindTexture");
2049 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2050 checkGLcall("glTexImage2D");
2052 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2053 /* Reenable because if supported it is enabled by default */
2054 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2055 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2058 LEAVE_GL();
2061 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2062 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2063 IWineD3DSwapChainImpl *swapchain = NULL;
2064 HRESULT hr;
2065 DWORD state;
2066 unsigned int i;
2068 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2069 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2070 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2072 /* TODO: Test if OpenGL is compiled in and loaded */
2074 TRACE("(%p) : Creating stateblock\n", This);
2075 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2076 hr = IWineD3DDevice_CreateStateBlock(iface,
2077 WINED3DSBT_INIT,
2078 (IWineD3DStateBlock **)&This->stateBlock,
2079 NULL);
2080 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2081 WARN("Failed to create stateblock\n");
2082 goto err_out;
2084 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2085 This->updateStateBlock = This->stateBlock;
2086 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2088 hr = allocate_shader_constants(This->updateStateBlock);
2089 if (WINED3D_OK != hr) {
2090 goto err_out;
2093 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2094 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2095 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2097 This->NumberOfPalettes = 1;
2098 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2099 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2100 ERR("Out of memory!\n");
2101 goto err_out;
2103 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2104 if(!This->palettes[0]) {
2105 ERR("Out of memory!\n");
2106 goto err_out;
2108 for (i = 0; i < 256; ++i) {
2109 This->palettes[0][i].peRed = 0xFF;
2110 This->palettes[0][i].peGreen = 0xFF;
2111 This->palettes[0][i].peBlue = 0xFF;
2112 This->palettes[0][i].peFlags = 0xFF;
2114 This->currentPalette = 0;
2116 /* Initialize the texture unit mapping to a 1:1 mapping */
2117 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2118 if (state < GL_LIMITS(fragment_samplers)) {
2119 This->texUnitMap[state] = state;
2120 This->rev_tex_unit_map[state] = state;
2121 } else {
2122 This->texUnitMap[state] = -1;
2123 This->rev_tex_unit_map[state] = -1;
2127 /* Setup the implicit swapchain */
2128 TRACE("Creating implicit swapchain\n");
2129 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2130 if (FAILED(hr) || !swapchain) {
2131 WARN("Failed to create implicit swapchain\n");
2132 goto err_out;
2135 This->NumberOfSwapChains = 1;
2136 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2137 if(!This->swapchains) {
2138 ERR("Out of memory!\n");
2139 goto err_out;
2141 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2143 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2144 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2145 This->render_targets[0] = swapchain->backBuffer[0];
2146 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2148 else {
2149 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2150 This->render_targets[0] = swapchain->frontBuffer;
2151 This->lastActiveRenderTarget = swapchain->frontBuffer;
2153 IWineD3DSurface_AddRef(This->render_targets[0]);
2154 This->activeContext = swapchain->context[0];
2155 This->lastThread = GetCurrentThreadId();
2157 /* Depth Stencil support */
2158 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2159 if (NULL != This->stencilBufferTarget) {
2160 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2163 hr = This->shader_backend->shader_alloc_private(iface);
2164 if(FAILED(hr)) {
2165 TRACE("Shader private data couldn't be allocated\n");
2166 goto err_out;
2168 hr = This->frag_pipe->alloc_private(iface);
2169 if(FAILED(hr)) {
2170 TRACE("Fragment pipeline private data couldn't be allocated\n");
2171 goto err_out;
2173 hr = This->blitter->alloc_private(iface);
2174 if(FAILED(hr)) {
2175 TRACE("Blitter private data couldn't be allocated\n");
2176 goto err_out;
2179 /* Set up some starting GL setup */
2181 /* Setup all the devices defaults */
2182 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2183 create_dummy_textures(This);
2185 ENTER_GL();
2187 #if 0
2188 IWineD3DImpl_CheckGraphicsMemory();
2189 #endif
2191 { /* Set a default viewport */
2192 WINED3DVIEWPORT vp;
2193 vp.X = 0;
2194 vp.Y = 0;
2195 vp.Width = pPresentationParameters->BackBufferWidth;
2196 vp.Height = pPresentationParameters->BackBufferHeight;
2197 vp.MinZ = 0.0f;
2198 vp.MaxZ = 1.0f;
2199 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2202 /* Initialize the current view state */
2203 This->view_ident = 1;
2204 This->contexts[0]->last_was_rhw = 0;
2205 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2206 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2208 switch(wined3d_settings.offscreen_rendering_mode) {
2209 case ORM_FBO:
2210 case ORM_PBUFFER:
2211 This->offscreenBuffer = GL_BACK;
2212 break;
2214 case ORM_BACKBUFFER:
2216 if(This->activeContext->aux_buffers > 0) {
2217 TRACE("Using auxilliary buffer for offscreen rendering\n");
2218 This->offscreenBuffer = GL_AUX0;
2219 } else {
2220 TRACE("Using back buffer for offscreen rendering\n");
2221 This->offscreenBuffer = GL_BACK;
2226 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2227 LEAVE_GL();
2229 /* Clear the screen */
2230 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2231 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2232 0x00, 1.0, 0);
2234 This->d3d_initialized = TRUE;
2236 if(wined3d_settings.logo) {
2237 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2239 This->highest_dirty_ps_const = 0;
2240 This->highest_dirty_vs_const = 0;
2241 return WINED3D_OK;
2243 err_out:
2244 HeapFree(GetProcessHeap(), 0, This->render_targets);
2245 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2246 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2247 HeapFree(GetProcessHeap(), 0, This->swapchains);
2248 This->NumberOfSwapChains = 0;
2249 if(This->palettes) {
2250 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2251 HeapFree(GetProcessHeap(), 0, This->palettes);
2253 This->NumberOfPalettes = 0;
2254 if(swapchain) {
2255 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2257 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2258 if(This->stateBlock) {
2259 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2260 This->stateBlock = NULL;
2262 This->blitter->free_private(iface);
2263 This->frag_pipe->free_private(iface);
2264 This->shader_backend->shader_free_private(iface);
2265 return hr;
2268 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2270 IWineD3DSwapChainImpl *swapchain = NULL;
2271 HRESULT hr;
2273 /* Setup the implicit swapchain */
2274 TRACE("Creating implicit swapchain\n");
2275 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2276 if (FAILED(hr) || !swapchain) {
2277 WARN("Failed to create implicit swapchain\n");
2278 goto err_out;
2281 This->NumberOfSwapChains = 1;
2282 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2283 if(!This->swapchains) {
2284 ERR("Out of memory!\n");
2285 goto err_out;
2287 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2288 return WINED3D_OK;
2290 err_out:
2291 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2292 return hr;
2295 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2296 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2297 int sampler;
2298 UINT i;
2299 TRACE("(%p)\n", This);
2301 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2303 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2304 * it was created. Thus make sure a context is active for the glDelete* calls
2306 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2308 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2310 TRACE("Deleting high order patches\n");
2311 for(i = 0; i < PATCHMAP_SIZE; i++) {
2312 struct list *e1, *e2;
2313 struct WineD3DRectPatch *patch;
2314 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2315 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2316 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2320 /* Delete the palette conversion shader if it is around */
2321 if(This->paletteConversionShader) {
2322 ENTER_GL();
2323 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2324 LEAVE_GL();
2325 This->paletteConversionShader = 0;
2328 /* Delete the pbuffer context if there is any */
2329 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2331 /* Delete the mouse cursor texture */
2332 if(This->cursorTexture) {
2333 ENTER_GL();
2334 glDeleteTextures(1, &This->cursorTexture);
2335 LEAVE_GL();
2336 This->cursorTexture = 0;
2339 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2340 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2342 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2343 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2346 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2347 * private data, it might contain opengl pointers
2349 if(This->depth_blt_texture) {
2350 glDeleteTextures(1, &This->depth_blt_texture);
2351 This->depth_blt_texture = 0;
2353 if (This->depth_blt_rb) {
2354 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2355 This->depth_blt_rb = 0;
2356 This->depth_blt_rb_w = 0;
2357 This->depth_blt_rb_h = 0;
2360 /* Release the update stateblock */
2361 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2362 if(This->updateStateBlock != This->stateBlock)
2363 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2365 This->updateStateBlock = NULL;
2367 { /* because were not doing proper internal refcounts releasing the primary state block
2368 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2369 to set this->stateBlock = NULL; first */
2370 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2371 This->stateBlock = NULL;
2373 /* Release the stateblock */
2374 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2375 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2379 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2380 This->blitter->free_private(iface);
2381 This->frag_pipe->free_private(iface);
2382 This->shader_backend->shader_free_private(iface);
2384 /* Release the buffers (with sanity checks)*/
2385 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2386 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2387 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2388 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2390 This->stencilBufferTarget = NULL;
2392 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2393 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2394 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2396 TRACE("Setting rendertarget to NULL\n");
2397 This->render_targets[0] = NULL;
2399 if (This->auto_depth_stencil_buffer) {
2400 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2401 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2403 This->auto_depth_stencil_buffer = NULL;
2406 for(i=0; i < This->NumberOfSwapChains; i++) {
2407 TRACE("Releasing the implicit swapchain %d\n", i);
2408 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2409 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2413 HeapFree(GetProcessHeap(), 0, This->swapchains);
2414 This->swapchains = NULL;
2415 This->NumberOfSwapChains = 0;
2417 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2418 HeapFree(GetProcessHeap(), 0, This->palettes);
2419 This->palettes = NULL;
2420 This->NumberOfPalettes = 0;
2422 HeapFree(GetProcessHeap(), 0, This->render_targets);
2423 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2424 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2425 This->render_targets = NULL;
2426 This->fbo_color_attachments = NULL;
2427 This->draw_buffers = NULL;
2429 This->d3d_initialized = FALSE;
2430 return WINED3D_OK;
2433 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2434 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2435 unsigned int i;
2437 for(i=0; i < This->NumberOfSwapChains; i++) {
2438 TRACE("Releasing the implicit swapchain %d\n", i);
2439 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2440 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2444 HeapFree(GetProcessHeap(), 0, This->swapchains);
2445 This->swapchains = NULL;
2446 This->NumberOfSwapChains = 0;
2447 return WINED3D_OK;
2450 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2451 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2452 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2454 * There is no way to deactivate thread safety once it is enabled.
2456 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2457 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2459 /*For now just store the flag(needed in case of ddraw) */
2460 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2462 return;
2465 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2466 DEVMODEW devmode;
2467 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2468 LONG ret;
2469 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2470 RECT clip_rc;
2472 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2474 /* Resize the screen even without a window:
2475 * The app could have unset it with SetCooperativeLevel, but not called
2476 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2477 * but we don't have any hwnd
2480 memset(&devmode, 0, sizeof(devmode));
2481 devmode.dmSize = sizeof(devmode);
2482 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2483 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2484 devmode.dmPelsWidth = pMode->Width;
2485 devmode.dmPelsHeight = pMode->Height;
2487 devmode.dmDisplayFrequency = pMode->RefreshRate;
2488 if (pMode->RefreshRate != 0) {
2489 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2492 /* Only change the mode if necessary */
2493 if( (This->ddraw_width == pMode->Width) &&
2494 (This->ddraw_height == pMode->Height) &&
2495 (This->ddraw_format == pMode->Format) &&
2496 (pMode->RefreshRate == 0) ) {
2497 return WINED3D_OK;
2500 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2501 if (ret != DISP_CHANGE_SUCCESSFUL) {
2502 if(devmode.dmDisplayFrequency != 0) {
2503 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2504 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2505 devmode.dmDisplayFrequency = 0;
2506 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2508 if(ret != DISP_CHANGE_SUCCESSFUL) {
2509 return WINED3DERR_NOTAVAILABLE;
2513 /* Store the new values */
2514 This->ddraw_width = pMode->Width;
2515 This->ddraw_height = pMode->Height;
2516 This->ddraw_format = pMode->Format;
2518 /* And finally clip mouse to our screen */
2519 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2520 ClipCursor(&clip_rc);
2522 return WINED3D_OK;
2525 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2527 *ppD3D= This->wineD3D;
2528 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2529 IWineD3D_AddRef(*ppD3D);
2530 return WINED3D_OK;
2533 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2536 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2537 (This->adapter->TextureRam/(1024*1024)),
2538 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2539 /* return simulated texture memory left */
2540 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2545 /*****
2546 * Get / Set FVF
2547 *****/
2548 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2549 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2551 /* Update the current state block */
2552 This->updateStateBlock->changed.fvf = TRUE;
2554 if(This->updateStateBlock->fvf == fvf) {
2555 TRACE("Application is setting the old fvf over, nothing to do\n");
2556 return WINED3D_OK;
2559 This->updateStateBlock->fvf = fvf;
2560 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2561 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2562 return WINED3D_OK;
2566 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2568 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2569 *pfvf = This->stateBlock->fvf;
2570 return WINED3D_OK;
2573 /*****
2574 * Get / Set Stream Source
2575 *****/
2576 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2577 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2578 IWineD3DVertexBuffer *oldSrc;
2580 if (StreamNumber >= MAX_STREAMS) {
2581 WARN("Stream out of range %d\n", StreamNumber);
2582 return WINED3DERR_INVALIDCALL;
2583 } else if(OffsetInBytes & 0x3) {
2584 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2585 return WINED3DERR_INVALIDCALL;
2588 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2589 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2591 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2593 if(oldSrc == pStreamData &&
2594 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2595 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2596 TRACE("Application is setting the old values over, nothing to do\n");
2597 return WINED3D_OK;
2600 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2601 if (pStreamData) {
2602 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2603 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2606 /* Handle recording of state blocks */
2607 if (This->isRecordingState) {
2608 TRACE("Recording... not performing anything\n");
2609 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2610 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2611 return WINED3D_OK;
2614 /* Need to do a getParent and pass the references up */
2615 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2616 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2617 so for now, just count internally */
2618 if (pStreamData != NULL) {
2619 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2620 InterlockedIncrement(&vbImpl->bindCount);
2621 IWineD3DVertexBuffer_AddRef(pStreamData);
2623 if (oldSrc != NULL) {
2624 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2625 IWineD3DVertexBuffer_Release(oldSrc);
2628 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2630 return WINED3D_OK;
2633 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2634 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2636 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2637 This->stateBlock->streamSource[StreamNumber],
2638 This->stateBlock->streamOffset[StreamNumber],
2639 This->stateBlock->streamStride[StreamNumber]);
2641 if (StreamNumber >= MAX_STREAMS) {
2642 WARN("Stream out of range %d\n", StreamNumber);
2643 return WINED3DERR_INVALIDCALL;
2645 *pStream = This->stateBlock->streamSource[StreamNumber];
2646 *pStride = This->stateBlock->streamStride[StreamNumber];
2647 if (pOffset) {
2648 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2651 if (*pStream != NULL) {
2652 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2654 return WINED3D_OK;
2657 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2658 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2659 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2660 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2662 /* Verify input at least in d3d9 this is invalid*/
2663 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2664 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2665 return WINED3DERR_INVALIDCALL;
2667 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2668 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2669 return WINED3DERR_INVALIDCALL;
2671 if( Divider == 0 ){
2672 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2673 return WINED3DERR_INVALIDCALL;
2676 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2677 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2679 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2680 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2682 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2683 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2684 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2687 return WINED3D_OK;
2690 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2691 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2693 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2694 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2696 TRACE("(%p) : returning %d\n", This, *Divider);
2698 return WINED3D_OK;
2701 /*****
2702 * Get / Set & Multiply Transform
2703 *****/
2704 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2705 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2707 /* Most of this routine, comments included copied from ddraw tree initially: */
2708 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2710 /* Handle recording of state blocks */
2711 if (This->isRecordingState) {
2712 TRACE("Recording... not performing anything\n");
2713 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2714 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2715 return WINED3D_OK;
2719 * If the new matrix is the same as the current one,
2720 * we cut off any further processing. this seems to be a reasonable
2721 * optimization because as was noticed, some apps (warcraft3 for example)
2722 * tend towards setting the same matrix repeatedly for some reason.
2724 * From here on we assume that the new matrix is different, wherever it matters.
2726 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2727 TRACE("The app is setting the same matrix over again\n");
2728 return WINED3D_OK;
2729 } else {
2730 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2734 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2735 where ViewMat = Camera space, WorldMat = world space.
2737 In OpenGL, camera and world space is combined into GL_MODELVIEW
2738 matrix. The Projection matrix stay projection matrix.
2741 /* Capture the times we can just ignore the change for now */
2742 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2743 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2744 /* Handled by the state manager */
2747 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2748 return WINED3D_OK;
2751 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2753 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2754 *pMatrix = This->stateBlock->transforms[State];
2755 return WINED3D_OK;
2758 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2759 WINED3DMATRIX *mat = NULL;
2760 WINED3DMATRIX temp;
2762 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2763 * below means it will be recorded in a state block change, but it
2764 * works regardless where it is recorded.
2765 * If this is found to be wrong, change to StateBlock.
2767 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2768 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2770 if (State < HIGHEST_TRANSFORMSTATE)
2772 mat = &This->updateStateBlock->transforms[State];
2773 } else {
2774 FIXME("Unhandled transform state!!\n");
2777 multiply_matrix(&temp, mat, pMatrix);
2779 /* Apply change via set transform - will reapply to eg. lights this way */
2780 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2783 /*****
2784 * Get / Set Light
2785 *****/
2786 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2787 you can reference any indexes you want as long as that number max are enabled at any
2788 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2789 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2790 but when recording, just build a chain pretty much of commands to be replayed. */
2792 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2793 float rho;
2794 PLIGHTINFOEL *object = NULL;
2795 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2796 struct list *e;
2798 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2799 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2801 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2802 * the gl driver.
2804 if(!pLight) {
2805 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2806 return WINED3DERR_INVALIDCALL;
2809 switch(pLight->Type) {
2810 case WINED3DLIGHT_POINT:
2811 case WINED3DLIGHT_SPOT:
2812 case WINED3DLIGHT_PARALLELPOINT:
2813 case WINED3DLIGHT_GLSPOT:
2814 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2815 * most wanted
2817 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2818 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2819 return WINED3DERR_INVALIDCALL;
2821 break;
2823 case WINED3DLIGHT_DIRECTIONAL:
2824 /* Ignores attenuation */
2825 break;
2827 default:
2828 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2829 return WINED3DERR_INVALIDCALL;
2832 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2833 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2834 if(object->OriginalIndex == Index) break;
2835 object = NULL;
2838 if(!object) {
2839 TRACE("Adding new light\n");
2840 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2841 if(!object) {
2842 ERR("Out of memory error when allocating a light\n");
2843 return E_OUTOFMEMORY;
2845 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2846 object->glIndex = -1;
2847 object->OriginalIndex = Index;
2848 object->changed = TRUE;
2851 /* Initialize the object */
2852 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,
2853 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2854 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2855 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2856 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2857 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2858 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2860 /* Save away the information */
2861 object->OriginalParms = *pLight;
2863 switch (pLight->Type) {
2864 case WINED3DLIGHT_POINT:
2865 /* Position */
2866 object->lightPosn[0] = pLight->Position.x;
2867 object->lightPosn[1] = pLight->Position.y;
2868 object->lightPosn[2] = pLight->Position.z;
2869 object->lightPosn[3] = 1.0f;
2870 object->cutoff = 180.0f;
2871 /* FIXME: Range */
2872 break;
2874 case WINED3DLIGHT_DIRECTIONAL:
2875 /* Direction */
2876 object->lightPosn[0] = -pLight->Direction.x;
2877 object->lightPosn[1] = -pLight->Direction.y;
2878 object->lightPosn[2] = -pLight->Direction.z;
2879 object->lightPosn[3] = 0.0;
2880 object->exponent = 0.0f;
2881 object->cutoff = 180.0f;
2882 break;
2884 case WINED3DLIGHT_SPOT:
2885 /* Position */
2886 object->lightPosn[0] = pLight->Position.x;
2887 object->lightPosn[1] = pLight->Position.y;
2888 object->lightPosn[2] = pLight->Position.z;
2889 object->lightPosn[3] = 1.0;
2891 /* Direction */
2892 object->lightDirn[0] = pLight->Direction.x;
2893 object->lightDirn[1] = pLight->Direction.y;
2894 object->lightDirn[2] = pLight->Direction.z;
2895 object->lightDirn[3] = 1.0;
2898 * opengl-ish and d3d-ish spot lights use too different models for the
2899 * light "intensity" as a function of the angle towards the main light direction,
2900 * so we only can approximate very roughly.
2901 * however spot lights are rather rarely used in games (if ever used at all).
2902 * furthermore if still used, probably nobody pays attention to such details.
2904 if (pLight->Falloff == 0) {
2905 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2906 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2907 * will always be 1.0 for both of them, and we don't have to care for the
2908 * rest of the rather complex calculation
2910 object->exponent = 0;
2911 } else {
2912 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2913 if (rho < 0.0001) rho = 0.0001f;
2914 object->exponent = -0.3/log(cos(rho/2));
2916 if (object->exponent > 128.0) {
2917 object->exponent = 128.0;
2919 object->cutoff = pLight->Phi*90/M_PI;
2921 /* FIXME: Range */
2922 break;
2924 default:
2925 FIXME("Unrecognized light type %d\n", pLight->Type);
2928 /* Update the live definitions if the light is currently assigned a glIndex */
2929 if (object->glIndex != -1 && !This->isRecordingState) {
2930 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2932 return WINED3D_OK;
2935 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2936 PLIGHTINFOEL *lightInfo = NULL;
2937 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2938 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2939 struct list *e;
2940 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2942 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2943 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2944 if(lightInfo->OriginalIndex == Index) break;
2945 lightInfo = NULL;
2948 if (lightInfo == NULL) {
2949 TRACE("Light information requested but light not defined\n");
2950 return WINED3DERR_INVALIDCALL;
2953 *pLight = lightInfo->OriginalParms;
2954 return WINED3D_OK;
2957 /*****
2958 * Get / Set Light Enable
2959 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2960 *****/
2961 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2962 PLIGHTINFOEL *lightInfo = NULL;
2963 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2964 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2965 struct list *e;
2966 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2968 /* Tests show true = 128...not clear why */
2969 Enable = Enable? 128: 0;
2971 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2972 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2973 if(lightInfo->OriginalIndex == Index) break;
2974 lightInfo = NULL;
2976 TRACE("Found light: %p\n", lightInfo);
2978 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2979 if (lightInfo == NULL) {
2981 TRACE("Light enabled requested but light not defined, so defining one!\n");
2982 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2984 /* Search for it again! Should be fairly quick as near head of list */
2985 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2986 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2987 if(lightInfo->OriginalIndex == Index) break;
2988 lightInfo = NULL;
2990 if (lightInfo == NULL) {
2991 FIXME("Adding default lights has failed dismally\n");
2992 return WINED3DERR_INVALIDCALL;
2996 lightInfo->enabledChanged = TRUE;
2997 if(!Enable) {
2998 if(lightInfo->glIndex != -1) {
2999 if(!This->isRecordingState) {
3000 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3003 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
3004 lightInfo->glIndex = -1;
3005 } else {
3006 TRACE("Light already disabled, nothing to do\n");
3008 lightInfo->enabled = FALSE;
3009 } else {
3010 lightInfo->enabled = TRUE;
3011 if (lightInfo->glIndex != -1) {
3012 /* nop */
3013 TRACE("Nothing to do as light was enabled\n");
3014 } else {
3015 int i;
3016 /* Find a free gl light */
3017 for(i = 0; i < This->maxConcurrentLights; i++) {
3018 if(This->stateBlock->activeLights[i] == NULL) {
3019 This->stateBlock->activeLights[i] = lightInfo;
3020 lightInfo->glIndex = i;
3021 break;
3024 if(lightInfo->glIndex == -1) {
3025 /* Our tests show that Windows returns D3D_OK in this situation, even with
3026 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3027 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3028 * as well for those lights.
3030 * TODO: Test how this affects rendering
3032 FIXME("Too many concurrently active lights\n");
3033 return WINED3D_OK;
3036 /* i == lightInfo->glIndex */
3037 if(!This->isRecordingState) {
3038 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3043 return WINED3D_OK;
3046 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3048 PLIGHTINFOEL *lightInfo = NULL;
3049 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3050 struct list *e;
3051 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3052 TRACE("(%p) : for idx(%d)\n", This, Index);
3054 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3055 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3056 if(lightInfo->OriginalIndex == Index) break;
3057 lightInfo = NULL;
3060 if (lightInfo == NULL) {
3061 TRACE("Light enabled state requested but light not defined\n");
3062 return WINED3DERR_INVALIDCALL;
3064 /* true is 128 according to SetLightEnable */
3065 *pEnable = lightInfo->enabled ? 128 : 0;
3066 return WINED3D_OK;
3069 /*****
3070 * Get / Set Clip Planes
3071 *****/
3072 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3073 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3074 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3076 /* Validate Index */
3077 if (Index >= GL_LIMITS(clipplanes)) {
3078 TRACE("Application has requested clipplane this device doesn't support\n");
3079 return WINED3DERR_INVALIDCALL;
3082 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3084 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3085 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3086 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3087 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3088 TRACE("Application is setting old values over, nothing to do\n");
3089 return WINED3D_OK;
3092 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3093 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3094 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3095 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3097 /* Handle recording of state blocks */
3098 if (This->isRecordingState) {
3099 TRACE("Recording... not performing anything\n");
3100 return WINED3D_OK;
3103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3105 return WINED3D_OK;
3108 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3109 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3110 TRACE("(%p) : for idx %d\n", This, Index);
3112 /* Validate Index */
3113 if (Index >= GL_LIMITS(clipplanes)) {
3114 TRACE("Application has requested clipplane this device doesn't support\n");
3115 return WINED3DERR_INVALIDCALL;
3118 pPlane[0] = This->stateBlock->clipplane[Index][0];
3119 pPlane[1] = This->stateBlock->clipplane[Index][1];
3120 pPlane[2] = This->stateBlock->clipplane[Index][2];
3121 pPlane[3] = This->stateBlock->clipplane[Index][3];
3122 return WINED3D_OK;
3125 /*****
3126 * Get / Set Clip Plane Status
3127 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3128 *****/
3129 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3130 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3131 FIXME("(%p) : stub\n", This);
3132 if (NULL == pClipStatus) {
3133 return WINED3DERR_INVALIDCALL;
3135 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3136 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3137 return WINED3D_OK;
3140 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3141 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3142 FIXME("(%p) : stub\n", This);
3143 if (NULL == pClipStatus) {
3144 return WINED3DERR_INVALIDCALL;
3146 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3147 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3148 return WINED3D_OK;
3151 /*****
3152 * Get / Set Material
3153 *****/
3154 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3155 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3157 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3159 This->updateStateBlock->changed.material = TRUE;
3160 This->updateStateBlock->material = *pMaterial;
3162 /* Handle recording of state blocks */
3163 if (This->isRecordingState) {
3164 TRACE("Recording... not performing anything\n");
3165 return WINED3D_OK;
3168 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3169 return WINED3D_OK;
3172 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3174 *pMaterial = This->updateStateBlock->material;
3175 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3176 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3177 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3178 pMaterial->Ambient.b, pMaterial->Ambient.a);
3179 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3180 pMaterial->Specular.b, pMaterial->Specular.a);
3181 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3182 pMaterial->Emissive.b, pMaterial->Emissive.a);
3183 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3185 return WINED3D_OK;
3188 /*****
3189 * Get / Set Indices
3190 *****/
3191 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3193 IWineD3DIndexBuffer *oldIdxs;
3195 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3196 oldIdxs = This->updateStateBlock->pIndexData;
3198 This->updateStateBlock->changed.indices = TRUE;
3199 This->updateStateBlock->pIndexData = pIndexData;
3201 /* Handle recording of state blocks */
3202 if (This->isRecordingState) {
3203 TRACE("Recording... not performing anything\n");
3204 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3205 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3206 return WINED3D_OK;
3209 if(oldIdxs != pIndexData) {
3210 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3211 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3212 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3214 return WINED3D_OK;
3217 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3218 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3220 *ppIndexData = This->stateBlock->pIndexData;
3222 /* up ref count on ppindexdata */
3223 if (*ppIndexData) {
3224 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3225 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3226 }else{
3227 TRACE("(%p) No index data set\n", This);
3229 TRACE("Returning %p\n", *ppIndexData);
3231 return WINED3D_OK;
3234 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3235 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3237 TRACE("(%p)->(%d)\n", This, BaseIndex);
3239 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3240 TRACE("Application is setting the old value over, nothing to do\n");
3241 return WINED3D_OK;
3244 This->updateStateBlock->baseVertexIndex = BaseIndex;
3246 if (This->isRecordingState) {
3247 TRACE("Recording... not performing anything\n");
3248 return WINED3D_OK;
3250 /* The base vertex index affects the stream sources */
3251 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3252 return WINED3D_OK;
3255 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3256 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3257 TRACE("(%p) : base_index %p\n", This, base_index);
3259 *base_index = This->stateBlock->baseVertexIndex;
3261 TRACE("Returning %u\n", *base_index);
3263 return WINED3D_OK;
3266 /*****
3267 * Get / Set Viewports
3268 *****/
3269 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3270 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3272 TRACE("(%p)\n", This);
3273 This->updateStateBlock->changed.viewport = TRUE;
3274 This->updateStateBlock->viewport = *pViewport;
3276 /* Handle recording of state blocks */
3277 if (This->isRecordingState) {
3278 TRACE("Recording... not performing anything\n");
3279 return WINED3D_OK;
3282 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3283 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3285 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3286 return WINED3D_OK;
3290 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3292 TRACE("(%p)\n", This);
3293 *pViewport = This->stateBlock->viewport;
3294 return WINED3D_OK;
3297 /*****
3298 * Get / Set Render States
3299 * TODO: Verify against dx9 definitions
3300 *****/
3301 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3304 DWORD oldValue = This->stateBlock->renderState[State];
3306 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3308 This->updateStateBlock->changed.renderState[State] = TRUE;
3309 This->updateStateBlock->renderState[State] = Value;
3311 /* Handle recording of state blocks */
3312 if (This->isRecordingState) {
3313 TRACE("Recording... not performing anything\n");
3314 return WINED3D_OK;
3317 /* Compared here and not before the assignment to allow proper stateblock recording */
3318 if(Value == oldValue) {
3319 TRACE("Application is setting the old value over, nothing to do\n");
3320 } else {
3321 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3324 return WINED3D_OK;
3327 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3329 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3330 *pValue = This->stateBlock->renderState[State];
3331 return WINED3D_OK;
3334 /*****
3335 * Get / Set Sampler States
3336 * TODO: Verify against dx9 definitions
3337 *****/
3339 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3340 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3341 DWORD oldValue;
3343 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3344 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3346 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3347 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3350 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3351 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3352 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3355 * SetSampler is designed to allow for more than the standard up to 8 textures
3356 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3357 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3359 * http://developer.nvidia.com/object/General_FAQ.html#t6
3361 * There are two new settings for GForce
3362 * the sampler one:
3363 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3364 * and the texture one:
3365 * GL_MAX_TEXTURE_COORDS_ARB.
3366 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3367 ******************/
3369 oldValue = This->stateBlock->samplerState[Sampler][Type];
3370 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3371 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3373 /* Handle recording of state blocks */
3374 if (This->isRecordingState) {
3375 TRACE("Recording... not performing anything\n");
3376 return WINED3D_OK;
3379 if(oldValue == Value) {
3380 TRACE("Application is setting the old value over, nothing to do\n");
3381 return WINED3D_OK;
3384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3386 return WINED3D_OK;
3389 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3390 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3392 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3393 This, Sampler, debug_d3dsamplerstate(Type), Type);
3395 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3396 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3399 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3400 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3401 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3403 *Value = This->stateBlock->samplerState[Sampler][Type];
3404 TRACE("(%p) : Returning %#x\n", This, *Value);
3406 return WINED3D_OK;
3409 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3412 This->updateStateBlock->changed.scissorRect = TRUE;
3413 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3414 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3415 return WINED3D_OK;
3417 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3419 if(This->isRecordingState) {
3420 TRACE("Recording... not performing anything\n");
3421 return WINED3D_OK;
3424 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3426 return WINED3D_OK;
3429 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3430 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3432 *pRect = This->updateStateBlock->scissorRect;
3433 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3434 return WINED3D_OK;
3437 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3438 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3439 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3441 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3443 This->updateStateBlock->vertexDecl = pDecl;
3444 This->updateStateBlock->changed.vertexDecl = TRUE;
3446 if (This->isRecordingState) {
3447 TRACE("Recording... not performing anything\n");
3448 return WINED3D_OK;
3449 } else if(pDecl == oldDecl) {
3450 /* Checked after the assignment to allow proper stateblock recording */
3451 TRACE("Application is setting the old declaration over, nothing to do\n");
3452 return WINED3D_OK;
3455 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3456 return WINED3D_OK;
3459 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3464 *ppDecl = This->stateBlock->vertexDecl;
3465 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3466 return WINED3D_OK;
3469 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3470 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3471 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3473 This->updateStateBlock->vertexShader = pShader;
3474 This->updateStateBlock->changed.vertexShader = TRUE;
3476 if (This->isRecordingState) {
3477 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3478 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3479 TRACE("Recording... not performing anything\n");
3480 return WINED3D_OK;
3481 } else if(oldShader == pShader) {
3482 /* Checked here to allow proper stateblock recording */
3483 TRACE("App is setting the old shader over, nothing to do\n");
3484 return WINED3D_OK;
3487 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3488 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3489 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3491 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3493 return WINED3D_OK;
3496 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3497 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3499 if (NULL == ppShader) {
3500 return WINED3DERR_INVALIDCALL;
3502 *ppShader = This->stateBlock->vertexShader;
3503 if( NULL != *ppShader)
3504 IWineD3DVertexShader_AddRef(*ppShader);
3506 TRACE("(%p) : returning %p\n", This, *ppShader);
3507 return WINED3D_OK;
3510 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3511 IWineD3DDevice *iface,
3512 UINT start,
3513 CONST BOOL *srcData,
3514 UINT count) {
3516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 int i, cnt = min(count, MAX_CONST_B - start);
3519 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3520 iface, srcData, start, count);
3522 if (srcData == NULL || cnt < 0)
3523 return WINED3DERR_INVALIDCALL;
3525 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3526 for (i = 0; i < cnt; i++)
3527 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3529 for (i = start; i < cnt + start; ++i) {
3530 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3533 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3535 return WINED3D_OK;
3538 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3539 IWineD3DDevice *iface,
3540 UINT start,
3541 BOOL *dstData,
3542 UINT count) {
3544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3545 int cnt = min(count, MAX_CONST_B - start);
3547 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3548 iface, dstData, start, count);
3550 if (dstData == NULL || cnt < 0)
3551 return WINED3DERR_INVALIDCALL;
3553 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3554 return WINED3D_OK;
3557 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3558 IWineD3DDevice *iface,
3559 UINT start,
3560 CONST int *srcData,
3561 UINT count) {
3563 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3564 int i, cnt = min(count, MAX_CONST_I - start);
3566 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3567 iface, srcData, start, count);
3569 if (srcData == NULL || cnt < 0)
3570 return WINED3DERR_INVALIDCALL;
3572 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3573 for (i = 0; i < cnt; i++)
3574 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3575 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3577 for (i = start; i < cnt + start; ++i) {
3578 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3581 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3583 return WINED3D_OK;
3586 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3587 IWineD3DDevice *iface,
3588 UINT start,
3589 int *dstData,
3590 UINT count) {
3592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3593 int cnt = min(count, MAX_CONST_I - start);
3595 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3596 iface, dstData, start, count);
3598 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3599 return WINED3DERR_INVALIDCALL;
3601 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3602 return WINED3D_OK;
3605 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3606 IWineD3DDevice *iface,
3607 UINT start,
3608 CONST float *srcData,
3609 UINT count) {
3611 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3612 int i;
3614 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3615 iface, srcData, start, count);
3617 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3618 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3619 return WINED3DERR_INVALIDCALL;
3621 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3622 if(TRACE_ON(d3d)) {
3623 for (i = 0; i < count; i++)
3624 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3625 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3628 for (i = start; i < count + start; ++i) {
3629 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3630 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3631 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3632 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3633 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3635 ptr->idx[ptr->count++] = i;
3636 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3640 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3642 return WINED3D_OK;
3645 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3646 IWineD3DDevice *iface,
3647 UINT start,
3648 CONST float *srcData,
3649 UINT count) {
3651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3652 int i;
3654 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3655 iface, srcData, start, count);
3657 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3658 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3659 return WINED3DERR_INVALIDCALL;
3661 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3662 if(TRACE_ON(d3d)) {
3663 for (i = 0; i < count; i++)
3664 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3665 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3668 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3669 * context. On a context switch the old context will be fully dirtified
3671 memset(This->activeContext->vshader_const_dirty + start, 1,
3672 sizeof(*This->activeContext->vshader_const_dirty) * count);
3673 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3675 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3677 return WINED3D_OK;
3680 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3681 IWineD3DDevice *iface,
3682 UINT start,
3683 float *dstData,
3684 UINT count) {
3686 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3687 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3689 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3690 iface, dstData, start, count);
3692 if (dstData == NULL || cnt < 0)
3693 return WINED3DERR_INVALIDCALL;
3695 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3696 return WINED3D_OK;
3699 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3700 DWORD i;
3701 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3706 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3707 int i = This->rev_tex_unit_map[unit];
3708 int j = This->texUnitMap[stage];
3710 This->texUnitMap[stage] = unit;
3711 if (i != -1 && i != stage) {
3712 This->texUnitMap[i] = -1;
3715 This->rev_tex_unit_map[unit] = stage;
3716 if (j != -1 && j != unit) {
3717 This->rev_tex_unit_map[j] = -1;
3721 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3722 int i;
3724 for (i = 0; i < MAX_TEXTURES; ++i) {
3725 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3726 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3727 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3728 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3729 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3730 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3731 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3732 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3734 if (color_op == WINED3DTOP_DISABLE) {
3735 /* Not used, and disable higher stages */
3736 while (i < MAX_TEXTURES) {
3737 This->fixed_function_usage_map[i] = FALSE;
3738 ++i;
3740 break;
3743 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3744 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3745 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3746 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3747 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3748 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3749 This->fixed_function_usage_map[i] = TRUE;
3750 } else {
3751 This->fixed_function_usage_map[i] = FALSE;
3754 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3755 This->fixed_function_usage_map[i+1] = TRUE;
3760 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3761 int i, tex;
3763 device_update_fixed_function_usage_map(This);
3765 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3766 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3767 if (!This->fixed_function_usage_map[i]) continue;
3769 if (This->texUnitMap[i] != i) {
3770 device_map_stage(This, i, i);
3771 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3772 markTextureStagesDirty(This, i);
3775 return;
3778 /* Now work out the mapping */
3779 tex = 0;
3780 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3781 if (!This->fixed_function_usage_map[i]) continue;
3783 if (This->texUnitMap[i] != tex) {
3784 device_map_stage(This, i, tex);
3785 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3786 markTextureStagesDirty(This, i);
3789 ++tex;
3793 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3794 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3795 int i;
3797 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3798 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3799 device_map_stage(This, i, i);
3800 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3801 if (i < MAX_TEXTURES) {
3802 markTextureStagesDirty(This, i);
3808 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3809 int current_mapping = This->rev_tex_unit_map[unit];
3811 if (current_mapping == -1) {
3812 /* Not currently used */
3813 return TRUE;
3816 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3817 /* Used by a fragment sampler */
3819 if (!pshader_sampler_tokens) {
3820 /* No pixel shader, check fixed function */
3821 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3824 /* Pixel shader, check the shader's sampler map */
3825 return !pshader_sampler_tokens[current_mapping];
3828 /* Used by a vertex sampler */
3829 return !vshader_sampler_tokens[current_mapping];
3832 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3833 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3834 DWORD *pshader_sampler_tokens = NULL;
3835 int start = GL_LIMITS(combined_samplers) - 1;
3836 int i;
3838 if (ps) {
3839 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3841 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3842 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3843 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3846 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3847 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3848 if (vshader_sampler_tokens[i]) {
3849 if (This->texUnitMap[vsampler_idx] != -1) {
3850 /* Already mapped somewhere */
3851 continue;
3854 while (start >= 0) {
3855 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3856 device_map_stage(This, vsampler_idx, start);
3857 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3859 --start;
3860 break;
3863 --start;
3869 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3870 BOOL vs = use_vs(This);
3871 BOOL ps = use_ps(This);
3873 * Rules are:
3874 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3875 * that would be really messy and require shader recompilation
3876 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3877 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3879 if (ps) {
3880 device_map_psamplers(This);
3881 } else {
3882 device_map_fixed_function_samplers(This);
3885 if (vs) {
3886 device_map_vsamplers(This, ps);
3890 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3891 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3892 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3893 This->updateStateBlock->pixelShader = pShader;
3894 This->updateStateBlock->changed.pixelShader = TRUE;
3896 /* Handle recording of state blocks */
3897 if (This->isRecordingState) {
3898 TRACE("Recording... not performing anything\n");
3901 if (This->isRecordingState) {
3902 TRACE("Recording... not performing anything\n");
3903 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3904 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3905 return WINED3D_OK;
3908 if(pShader == oldShader) {
3909 TRACE("App is setting the old pixel shader over, nothing to do\n");
3910 return WINED3D_OK;
3913 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3914 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3916 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3917 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3919 return WINED3D_OK;
3922 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3923 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3925 if (NULL == ppShader) {
3926 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3927 return WINED3DERR_INVALIDCALL;
3930 *ppShader = This->stateBlock->pixelShader;
3931 if (NULL != *ppShader) {
3932 IWineD3DPixelShader_AddRef(*ppShader);
3934 TRACE("(%p) : returning %p\n", This, *ppShader);
3935 return WINED3D_OK;
3938 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3939 IWineD3DDevice *iface,
3940 UINT start,
3941 CONST BOOL *srcData,
3942 UINT count) {
3944 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3945 int i, cnt = min(count, MAX_CONST_B - start);
3947 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3948 iface, srcData, start, count);
3950 if (srcData == NULL || cnt < 0)
3951 return WINED3DERR_INVALIDCALL;
3953 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3954 for (i = 0; i < cnt; i++)
3955 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3957 for (i = start; i < cnt + start; ++i) {
3958 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3963 return WINED3D_OK;
3966 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3967 IWineD3DDevice *iface,
3968 UINT start,
3969 BOOL *dstData,
3970 UINT count) {
3972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3973 int cnt = min(count, MAX_CONST_B - start);
3975 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3976 iface, dstData, start, count);
3978 if (dstData == NULL || cnt < 0)
3979 return WINED3DERR_INVALIDCALL;
3981 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3982 return WINED3D_OK;
3985 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3986 IWineD3DDevice *iface,
3987 UINT start,
3988 CONST int *srcData,
3989 UINT count) {
3991 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3992 int i, cnt = min(count, MAX_CONST_I - start);
3994 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3995 iface, srcData, start, count);
3997 if (srcData == NULL || cnt < 0)
3998 return WINED3DERR_INVALIDCALL;
4000 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4001 for (i = 0; i < cnt; i++)
4002 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4003 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4005 for (i = start; i < cnt + start; ++i) {
4006 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4009 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4011 return WINED3D_OK;
4014 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4015 IWineD3DDevice *iface,
4016 UINT start,
4017 int *dstData,
4018 UINT count) {
4020 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4021 int cnt = min(count, MAX_CONST_I - start);
4023 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4024 iface, dstData, start, count);
4026 if (dstData == NULL || cnt < 0)
4027 return WINED3DERR_INVALIDCALL;
4029 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4030 return WINED3D_OK;
4033 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4034 IWineD3DDevice *iface,
4035 UINT start,
4036 CONST float *srcData,
4037 UINT count) {
4039 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4040 int i;
4042 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4043 iface, srcData, start, count);
4045 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4046 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4047 return WINED3DERR_INVALIDCALL;
4049 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4050 if(TRACE_ON(d3d)) {
4051 for (i = 0; i < count; i++)
4052 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4053 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4056 for (i = start; i < count + start; ++i) {
4057 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4058 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4059 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4060 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4061 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4063 ptr->idx[ptr->count++] = i;
4064 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4068 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4070 return WINED3D_OK;
4073 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4074 IWineD3DDevice *iface,
4075 UINT start,
4076 CONST float *srcData,
4077 UINT count) {
4079 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4080 int i;
4082 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4083 iface, srcData, start, count);
4085 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4086 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4087 return WINED3DERR_INVALIDCALL;
4089 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4090 if(TRACE_ON(d3d)) {
4091 for (i = 0; i < count; i++)
4092 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4093 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4096 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4097 * context. On a context switch the old context will be fully dirtified
4099 memset(This->activeContext->pshader_const_dirty + start, 1,
4100 sizeof(*This->activeContext->pshader_const_dirty) * count);
4101 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4103 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4105 return WINED3D_OK;
4108 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4109 IWineD3DDevice *iface,
4110 UINT start,
4111 float *dstData,
4112 UINT count) {
4114 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4115 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4117 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4118 iface, dstData, start, count);
4120 if (dstData == NULL || cnt < 0)
4121 return WINED3DERR_INVALIDCALL;
4123 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4124 return WINED3D_OK;
4127 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4128 static HRESULT
4129 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4130 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4131 unsigned int i;
4132 DWORD DestFVF = dest->fvf;
4133 WINED3DVIEWPORT vp;
4134 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4135 BOOL doClip;
4136 int numTextures;
4138 if (lpStrideData->u.s.normal.lpData) {
4139 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4142 if (lpStrideData->u.s.position.lpData == NULL) {
4143 ERR("Source has no position mask\n");
4144 return WINED3DERR_INVALIDCALL;
4147 /* We might access VBOs from this code, so hold the lock */
4148 ENTER_GL();
4150 if (dest->resource.allocatedMemory == NULL) {
4151 /* This may happen if we do direct locking into a vbo. Unlikely,
4152 * but theoretically possible(ddraw processvertices test)
4154 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4155 if(!dest->resource.allocatedMemory) {
4156 LEAVE_GL();
4157 ERR("Out of memory\n");
4158 return E_OUTOFMEMORY;
4160 if(dest->vbo) {
4161 void *src;
4162 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4163 checkGLcall("glBindBufferARB");
4164 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4165 if(src) {
4166 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4168 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4169 checkGLcall("glUnmapBufferARB");
4173 /* Get a pointer into the destination vbo(create one if none exists) and
4174 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4176 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4177 dest->Flags |= VBFLAG_CREATEVBO;
4178 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4181 if(dest->vbo) {
4182 unsigned char extrabytes = 0;
4183 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4184 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4185 * this may write 4 extra bytes beyond the area that should be written
4187 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4188 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4189 if(!dest_conv_addr) {
4190 ERR("Out of memory\n");
4191 /* Continue without storing converted vertices */
4193 dest_conv = dest_conv_addr;
4196 /* Should I clip?
4197 * a) WINED3DRS_CLIPPING is enabled
4198 * b) WINED3DVOP_CLIP is passed
4200 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4201 static BOOL warned = FALSE;
4203 * The clipping code is not quite correct. Some things need
4204 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4205 * so disable clipping for now.
4206 * (The graphics in Half-Life are broken, and my processvertices
4207 * test crashes with IDirect3DDevice3)
4208 doClip = TRUE;
4210 doClip = FALSE;
4211 if(!warned) {
4212 warned = TRUE;
4213 FIXME("Clipping is broken and disabled for now\n");
4215 } else doClip = FALSE;
4216 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4218 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4219 WINED3DTS_VIEW,
4220 &view_mat);
4221 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4222 WINED3DTS_PROJECTION,
4223 &proj_mat);
4224 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4225 WINED3DTS_WORLDMATRIX(0),
4226 &world_mat);
4228 TRACE("View mat:\n");
4229 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);
4230 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);
4231 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);
4232 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);
4234 TRACE("Proj mat:\n");
4235 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);
4236 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);
4237 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);
4238 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);
4240 TRACE("World mat:\n");
4241 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);
4242 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);
4243 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);
4244 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);
4246 /* Get the viewport */
4247 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4248 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4249 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4251 multiply_matrix(&mat,&view_mat,&world_mat);
4252 multiply_matrix(&mat,&proj_mat,&mat);
4254 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4256 for (i = 0; i < dwCount; i+= 1) {
4257 unsigned int tex_index;
4259 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4260 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4261 /* The position first */
4262 float *p =
4263 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4264 float x, y, z, rhw;
4265 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4267 /* Multiplication with world, view and projection matrix */
4268 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);
4269 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);
4270 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);
4271 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);
4273 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4275 /* WARNING: The following things are taken from d3d7 and were not yet checked
4276 * against d3d8 or d3d9!
4279 /* Clipping conditions: From msdn
4281 * A vertex is clipped if it does not match the following requirements
4282 * -rhw < x <= rhw
4283 * -rhw < y <= rhw
4284 * 0 < z <= rhw
4285 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4287 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4288 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4292 if( !doClip ||
4293 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4294 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4295 ( rhw > eps ) ) ) {
4297 /* "Normal" viewport transformation (not clipped)
4298 * 1) The values are divided by rhw
4299 * 2) The y axis is negative, so multiply it with -1
4300 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4301 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4302 * 4) Multiply x with Width/2 and add Width/2
4303 * 5) The same for the height
4304 * 6) Add the viewpoint X and Y to the 2D coordinates and
4305 * The minimum Z value to z
4306 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4308 * Well, basically it's simply a linear transformation into viewport
4309 * coordinates
4312 x /= rhw;
4313 y /= rhw;
4314 z /= rhw;
4316 y *= -1;
4318 x *= vp.Width / 2;
4319 y *= vp.Height / 2;
4320 z *= vp.MaxZ - vp.MinZ;
4322 x += vp.Width / 2 + vp.X;
4323 y += vp.Height / 2 + vp.Y;
4324 z += vp.MinZ;
4326 rhw = 1 / rhw;
4327 } else {
4328 /* That vertex got clipped
4329 * Contrary to OpenGL it is not dropped completely, it just
4330 * undergoes a different calculation.
4332 TRACE("Vertex got clipped\n");
4333 x += rhw;
4334 y += rhw;
4336 x /= 2;
4337 y /= 2;
4339 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4340 * outside of the main vertex buffer memory. That needs some more
4341 * investigation...
4345 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4348 ( (float *) dest_ptr)[0] = x;
4349 ( (float *) dest_ptr)[1] = y;
4350 ( (float *) dest_ptr)[2] = z;
4351 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4353 dest_ptr += 3 * sizeof(float);
4355 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4356 dest_ptr += sizeof(float);
4359 if(dest_conv) {
4360 float w = 1 / rhw;
4361 ( (float *) dest_conv)[0] = x * w;
4362 ( (float *) dest_conv)[1] = y * w;
4363 ( (float *) dest_conv)[2] = z * w;
4364 ( (float *) dest_conv)[3] = w;
4366 dest_conv += 3 * sizeof(float);
4368 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4369 dest_conv += sizeof(float);
4373 if (DestFVF & WINED3DFVF_PSIZE) {
4374 dest_ptr += sizeof(DWORD);
4375 if(dest_conv) dest_conv += sizeof(DWORD);
4377 if (DestFVF & WINED3DFVF_NORMAL) {
4378 float *normal =
4379 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4380 /* AFAIK this should go into the lighting information */
4381 FIXME("Didn't expect the destination to have a normal\n");
4382 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4383 if(dest_conv) {
4384 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4388 if (DestFVF & WINED3DFVF_DIFFUSE) {
4389 DWORD *color_d =
4390 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4391 if(!color_d) {
4392 static BOOL warned = FALSE;
4394 if(!warned) {
4395 ERR("No diffuse color in source, but destination has one\n");
4396 warned = TRUE;
4399 *( (DWORD *) dest_ptr) = 0xffffffff;
4400 dest_ptr += sizeof(DWORD);
4402 if(dest_conv) {
4403 *( (DWORD *) dest_conv) = 0xffffffff;
4404 dest_conv += sizeof(DWORD);
4407 else {
4408 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4409 if(dest_conv) {
4410 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4411 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4412 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4413 dest_conv += sizeof(DWORD);
4418 if (DestFVF & WINED3DFVF_SPECULAR) {
4419 /* What's the color value in the feedback buffer? */
4420 DWORD *color_s =
4421 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4422 if(!color_s) {
4423 static BOOL warned = FALSE;
4425 if(!warned) {
4426 ERR("No specular color in source, but destination has one\n");
4427 warned = TRUE;
4430 *( (DWORD *) dest_ptr) = 0xFF000000;
4431 dest_ptr += sizeof(DWORD);
4433 if(dest_conv) {
4434 *( (DWORD *) dest_conv) = 0xFF000000;
4435 dest_conv += sizeof(DWORD);
4438 else {
4439 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4440 if(dest_conv) {
4441 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4442 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4443 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4444 dest_conv += sizeof(DWORD);
4449 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4450 float *tex_coord =
4451 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4452 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4453 if(!tex_coord) {
4454 ERR("No source texture, but destination requests one\n");
4455 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4456 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4458 else {
4459 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4460 if(dest_conv) {
4461 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4467 if(dest_conv) {
4468 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4469 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4470 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4471 dwCount * get_flexible_vertex_size(DestFVF),
4472 dest_conv_addr));
4473 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4474 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4477 LEAVE_GL();
4479 return WINED3D_OK;
4481 #undef copy_and_next
4483 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4484 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4485 WineDirect3DVertexStridedData strided;
4486 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4487 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4489 if(pVertexDecl) {
4490 ERR("Output vertex declaration not implemented yet\n");
4493 /* Need any context to write to the vbo. */
4494 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4496 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4497 * control the streamIsUP flag, thus restore it afterwards.
4499 This->stateBlock->streamIsUP = FALSE;
4500 memset(&strided, 0, sizeof(strided));
4501 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4502 This->stateBlock->streamIsUP = streamWasUP;
4504 if(vbo || SrcStartIndex) {
4505 unsigned int i;
4506 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4507 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4509 * Also get the start index in, but only loop over all elements if there's something to add at all.
4511 #define FIXSRC(type) \
4512 if(strided.u.s.type.VBO) { \
4513 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4514 strided.u.s.type.VBO = 0; \
4515 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4516 ENTER_GL(); \
4517 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4518 vb->vbo = 0; \
4519 LEAVE_GL(); \
4521 if(strided.u.s.type.lpData) { \
4522 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4524 FIXSRC(position);
4525 FIXSRC(blendWeights);
4526 FIXSRC(blendMatrixIndices);
4527 FIXSRC(normal);
4528 FIXSRC(pSize);
4529 FIXSRC(diffuse);
4530 FIXSRC(specular);
4531 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4532 FIXSRC(texCoords[i]);
4534 FIXSRC(position2);
4535 FIXSRC(normal2);
4536 FIXSRC(tangent);
4537 FIXSRC(binormal);
4538 FIXSRC(tessFactor);
4539 FIXSRC(fog);
4540 FIXSRC(depth);
4541 FIXSRC(sample);
4542 #undef FIXSRC
4545 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4548 /*****
4549 * Get / Set Texture Stage States
4550 * TODO: Verify against dx9 definitions
4551 *****/
4552 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4553 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4554 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4556 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4558 if (Stage >= MAX_TEXTURES) {
4559 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4560 return WINED3D_OK;
4563 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4564 This->updateStateBlock->textureState[Stage][Type] = Value;
4566 if (This->isRecordingState) {
4567 TRACE("Recording... not performing anything\n");
4568 return WINED3D_OK;
4571 /* Checked after the assignments to allow proper stateblock recording */
4572 if(oldValue == Value) {
4573 TRACE("App is setting the old value over, nothing to do\n");
4574 return WINED3D_OK;
4577 if(Stage > This->stateBlock->lowest_disabled_stage &&
4578 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4579 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4580 * Changes in other states are important on disabled stages too
4582 return WINED3D_OK;
4585 if(Type == WINED3DTSS_COLOROP) {
4586 int i;
4588 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4589 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4590 * they have to be disabled
4592 * The current stage is dirtified below.
4594 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4595 TRACE("Additionally dirtifying stage %d\n", i);
4596 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4598 This->stateBlock->lowest_disabled_stage = Stage;
4599 TRACE("New lowest disabled: %d\n", Stage);
4600 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4601 /* Previously disabled stage enabled. Stages above it may need enabling
4602 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4603 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4605 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4608 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4609 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4610 break;
4612 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4613 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4615 This->stateBlock->lowest_disabled_stage = i;
4616 TRACE("New lowest disabled: %d\n", i);
4618 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4619 /* TODO: Built a stage -> texture unit mapping for register combiners */
4623 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4625 return WINED3D_OK;
4628 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4630 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4631 *pValue = This->updateStateBlock->textureState[Stage][Type];
4632 return WINED3D_OK;
4635 /*****
4636 * Get / Set Texture
4637 *****/
4638 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4640 IWineD3DBaseTexture *oldTexture;
4642 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4644 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4645 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4648 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4649 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4650 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4653 oldTexture = This->updateStateBlock->textures[Stage];
4655 if(pTexture != NULL) {
4656 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4658 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4659 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4660 return WINED3DERR_INVALIDCALL;
4662 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4665 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4666 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4668 This->updateStateBlock->changed.textures[Stage] = TRUE;
4669 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4670 This->updateStateBlock->textures[Stage] = pTexture;
4672 /* Handle recording of state blocks */
4673 if (This->isRecordingState) {
4674 TRACE("Recording... not performing anything\n");
4675 return WINED3D_OK;
4678 if(oldTexture == pTexture) {
4679 TRACE("App is setting the same texture again, nothing to do\n");
4680 return WINED3D_OK;
4683 /** NOTE: MSDN says that setTexture increases the reference count,
4684 * and that the application must set the texture back to null (or have a leaky application),
4685 * This means we should pass the refcount up to the parent
4686 *******************************/
4687 if (NULL != This->updateStateBlock->textures[Stage]) {
4688 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4689 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4691 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4692 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4693 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4694 * so the COLOROP and ALPHAOP have to be dirtified.
4696 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4697 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4699 if(bindCount == 1) {
4700 new->baseTexture.sampler = Stage;
4702 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4706 if (NULL != oldTexture) {
4707 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4708 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4710 IWineD3DBaseTexture_Release(oldTexture);
4711 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4712 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4713 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4716 if(bindCount && old->baseTexture.sampler == Stage) {
4717 int i;
4718 /* Have to do a search for the other sampler(s) where the texture is bound to
4719 * Shouldn't happen as long as apps bind a texture only to one stage
4721 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4722 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4723 if(This->updateStateBlock->textures[i] == oldTexture) {
4724 old->baseTexture.sampler = i;
4725 break;
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4733 return WINED3D_OK;
4736 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4737 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4739 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4741 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4742 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4745 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4746 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4747 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4750 *ppTexture=This->stateBlock->textures[Stage];
4751 if (*ppTexture)
4752 IWineD3DBaseTexture_AddRef(*ppTexture);
4754 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4756 return WINED3D_OK;
4759 /*****
4760 * Get Back Buffer
4761 *****/
4762 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4763 IWineD3DSurface **ppBackBuffer) {
4764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4765 IWineD3DSwapChain *swapChain;
4766 HRESULT hr;
4768 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4770 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4771 if (hr == WINED3D_OK) {
4772 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4773 IWineD3DSwapChain_Release(swapChain);
4774 } else {
4775 *ppBackBuffer = NULL;
4777 return hr;
4780 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4782 WARN("(%p) : stub, calling idirect3d for now\n", This);
4783 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4786 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4787 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4788 IWineD3DSwapChain *swapChain;
4789 HRESULT hr;
4791 if(iSwapChain > 0) {
4792 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4793 if (hr == WINED3D_OK) {
4794 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4795 IWineD3DSwapChain_Release(swapChain);
4796 } else {
4797 FIXME("(%p) Error getting display mode\n", This);
4799 } else {
4800 /* Don't read the real display mode,
4801 but return the stored mode instead. X11 can't change the color
4802 depth, and some apps are pretty angry if they SetDisplayMode from
4803 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4805 Also don't relay to the swapchain because with ddraw it's possible
4806 that there isn't a swapchain at all */
4807 pMode->Width = This->ddraw_width;
4808 pMode->Height = This->ddraw_height;
4809 pMode->Format = This->ddraw_format;
4810 pMode->RefreshRate = 0;
4811 hr = WINED3D_OK;
4814 return hr;
4817 /*****
4818 * Stateblock related functions
4819 *****/
4821 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4822 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4823 IWineD3DStateBlockImpl *object;
4824 HRESULT temp_result;
4825 int i;
4827 TRACE("(%p)\n", This);
4829 if (This->isRecordingState) {
4830 return WINED3DERR_INVALIDCALL;
4833 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4834 if (NULL == object ) {
4835 FIXME("(%p)Error allocating memory for stateblock\n", This);
4836 return E_OUTOFMEMORY;
4838 TRACE("(%p) created object %p\n", This, object);
4839 object->wineD3DDevice= This;
4840 /** FIXME: object->parent = parent; **/
4841 object->parent = NULL;
4842 object->blockType = WINED3DSBT_RECORDED;
4843 object->ref = 1;
4844 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4846 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4847 list_init(&object->lightMap[i]);
4850 temp_result = allocate_shader_constants(object);
4851 if (WINED3D_OK != temp_result)
4852 return temp_result;
4854 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4855 This->updateStateBlock = object;
4856 This->isRecordingState = TRUE;
4858 TRACE("(%p) recording stateblock %p\n",This , object);
4859 return WINED3D_OK;
4862 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4864 unsigned int i, j;
4865 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4867 if (!This->isRecordingState) {
4868 FIXME("(%p) not recording! returning error\n", This);
4869 *ppStateBlock = NULL;
4870 return WINED3DERR_INVALIDCALL;
4873 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4874 if(object->changed.renderState[i]) {
4875 object->contained_render_states[object->num_contained_render_states] = i;
4876 object->num_contained_render_states++;
4879 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4880 if(object->changed.transform[i]) {
4881 object->contained_transform_states[object->num_contained_transform_states] = i;
4882 object->num_contained_transform_states++;
4885 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4886 if(object->changed.vertexShaderConstantsF[i]) {
4887 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4888 object->num_contained_vs_consts_f++;
4891 for(i = 0; i < MAX_CONST_I; i++) {
4892 if(object->changed.vertexShaderConstantsI[i]) {
4893 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4894 object->num_contained_vs_consts_i++;
4897 for(i = 0; i < MAX_CONST_B; i++) {
4898 if(object->changed.vertexShaderConstantsB[i]) {
4899 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4900 object->num_contained_vs_consts_b++;
4903 for(i = 0; i < MAX_CONST_I; i++) {
4904 if(object->changed.pixelShaderConstantsI[i]) {
4905 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4906 object->num_contained_ps_consts_i++;
4909 for(i = 0; i < MAX_CONST_B; i++) {
4910 if(object->changed.pixelShaderConstantsB[i]) {
4911 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4912 object->num_contained_ps_consts_b++;
4915 for(i = 0; i < MAX_TEXTURES; i++) {
4916 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4917 if(object->changed.textureState[i][j]) {
4918 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4919 object->contained_tss_states[object->num_contained_tss_states].state = j;
4920 object->num_contained_tss_states++;
4924 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4925 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4926 if(object->changed.samplerState[i][j]) {
4927 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4928 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4929 object->num_contained_sampler_states++;
4934 *ppStateBlock = (IWineD3DStateBlock*) object;
4935 This->isRecordingState = FALSE;
4936 This->updateStateBlock = This->stateBlock;
4937 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4938 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4939 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4940 return WINED3D_OK;
4943 /*****
4944 * Scene related functions
4945 *****/
4946 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4947 /* At the moment we have no need for any functionality at the beginning
4948 of a scene */
4949 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4950 TRACE("(%p)\n", This);
4952 if(This->inScene) {
4953 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4954 return WINED3DERR_INVALIDCALL;
4956 This->inScene = TRUE;
4957 return WINED3D_OK;
4960 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4961 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4962 TRACE("(%p)\n", This);
4964 if(!This->inScene) {
4965 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4966 return WINED3DERR_INVALIDCALL;
4969 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4970 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4971 glFlush();
4972 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4973 * fails
4976 This->inScene = FALSE;
4977 return WINED3D_OK;
4980 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4981 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4982 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4984 IWineD3DSwapChain *swapChain = NULL;
4985 int i;
4986 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4988 TRACE("(%p) Presenting the frame\n", This);
4990 for(i = 0 ; i < swapchains ; i ++) {
4992 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4993 TRACE("presentinng chain %d, %p\n", i, swapChain);
4994 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4995 IWineD3DSwapChain_Release(swapChain);
4998 return WINED3D_OK;
5001 /* Not called from the VTable (internal subroutine) */
5002 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5003 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5004 float Z, DWORD Stencil) {
5005 GLbitfield glMask = 0;
5006 unsigned int i;
5007 WINED3DRECT curRect;
5008 RECT vp_rect;
5009 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5010 UINT drawable_width, drawable_height;
5011 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5013 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5014 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5015 * for the cleared parts, and the untouched parts.
5017 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5018 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5019 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5020 * checking all this if the dest surface is in the drawable anyway.
5022 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5023 while(1) {
5024 if(vp->X != 0 || vp->Y != 0 ||
5025 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5026 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5027 break;
5029 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5030 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5031 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5032 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5033 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5034 break;
5036 if(Count > 0 && pRects && (
5037 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5038 pRects[0].x2 < target->currentDesc.Width ||
5039 pRects[0].y2 < target->currentDesc.Height)) {
5040 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5041 break;
5043 break;
5047 target->get_drawable_size(target, &drawable_width, &drawable_height);
5049 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5050 ENTER_GL();
5052 /* Only set the values up once, as they are not changing */
5053 if (Flags & WINED3DCLEAR_STENCIL) {
5054 glClearStencil(Stencil);
5055 checkGLcall("glClearStencil");
5056 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5057 glStencilMask(0xFFFFFFFF);
5060 if (Flags & WINED3DCLEAR_ZBUFFER) {
5061 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5062 glDepthMask(GL_TRUE);
5063 glClearDepth(Z);
5064 checkGLcall("glClearDepth");
5065 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5066 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5068 if (vp->X != 0 || vp->Y != 0 ||
5069 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5070 surface_load_ds_location(This->stencilBufferTarget, location);
5072 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5073 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5074 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5075 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5076 surface_load_ds_location(This->stencilBufferTarget, location);
5078 else if (Count > 0 && pRects && (
5079 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5080 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5081 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5082 surface_load_ds_location(This->stencilBufferTarget, location);
5086 if (Flags & WINED3DCLEAR_TARGET) {
5087 TRACE("Clearing screen with glClear to color %x\n", Color);
5088 glClearColor(D3DCOLOR_R(Color),
5089 D3DCOLOR_G(Color),
5090 D3DCOLOR_B(Color),
5091 D3DCOLOR_A(Color));
5092 checkGLcall("glClearColor");
5094 /* Clear ALL colors! */
5095 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5096 glMask = glMask | GL_COLOR_BUFFER_BIT;
5099 vp_rect.left = vp->X;
5100 vp_rect.top = vp->Y;
5101 vp_rect.right = vp->X + vp->Width;
5102 vp_rect.bottom = vp->Y + vp->Height;
5103 if (!(Count > 0 && pRects)) {
5104 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5105 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5107 if(This->render_offscreen) {
5108 glScissor(vp_rect.left, vp_rect.top,
5109 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5110 } else {
5111 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5112 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5114 checkGLcall("glScissor");
5115 glClear(glMask);
5116 checkGLcall("glClear");
5117 } else {
5118 /* Now process each rect in turn */
5119 for (i = 0; i < Count; i++) {
5120 /* Note gl uses lower left, width/height */
5121 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5122 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5123 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5125 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5126 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5127 curRect.x1, (target->currentDesc.Height - curRect.y2),
5128 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5130 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5131 * The rectangle is not cleared, no error is returned, but further rectanlges are
5132 * still cleared if they are valid
5134 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5135 TRACE("Rectangle with negative dimensions, ignoring\n");
5136 continue;
5139 if(This->render_offscreen) {
5140 glScissor(curRect.x1, curRect.y1,
5141 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5142 } else {
5143 glScissor(curRect.x1, drawable_height - curRect.y2,
5144 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5146 checkGLcall("glScissor");
5148 glClear(glMask);
5149 checkGLcall("glClear");
5153 /* Restore the old values (why..?) */
5154 if (Flags & WINED3DCLEAR_STENCIL) {
5155 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5157 if (Flags & WINED3DCLEAR_TARGET) {
5158 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5159 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5160 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5161 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5162 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5164 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5165 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5167 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5168 /* TODO: Move the fbo logic into ModifyLocation() */
5169 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5170 target->Flags |= SFLAG_INTEXTURE;
5173 if (Flags & WINED3DCLEAR_ZBUFFER) {
5174 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5175 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5176 surface_modify_ds_location(This->stencilBufferTarget, location);
5179 LEAVE_GL();
5181 return WINED3D_OK;
5184 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5185 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5186 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5187 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5189 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5190 Count, pRects, Flags, Color, Z, Stencil);
5192 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5193 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5194 /* TODO: What about depth stencil buffers without stencil bits? */
5195 return WINED3DERR_INVALIDCALL;
5198 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5201 /*****
5202 * Drawing functions
5203 *****/
5204 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5205 UINT PrimitiveCount) {
5207 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5209 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5210 debug_d3dprimitivetype(PrimitiveType),
5211 StartVertex, PrimitiveCount);
5213 if(!This->stateBlock->vertexDecl) {
5214 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5215 return WINED3DERR_INVALIDCALL;
5218 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5219 if(This->stateBlock->streamIsUP) {
5220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5221 This->stateBlock->streamIsUP = FALSE;
5224 if(This->stateBlock->loadBaseVertexIndex != 0) {
5225 This->stateBlock->loadBaseVertexIndex = 0;
5226 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5228 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5229 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5230 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5231 return WINED3D_OK;
5234 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5235 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5236 WINED3DPRIMITIVETYPE PrimitiveType,
5237 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5239 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5240 UINT idxStride = 2;
5241 IWineD3DIndexBuffer *pIB;
5242 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5243 GLuint vbo;
5245 pIB = This->stateBlock->pIndexData;
5246 if (!pIB) {
5247 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5248 * without an index buffer set. (The first time at least...)
5249 * D3D8 simply dies, but I doubt it can do much harm to return
5250 * D3DERR_INVALIDCALL there as well. */
5251 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5252 return WINED3DERR_INVALIDCALL;
5255 if(!This->stateBlock->vertexDecl) {
5256 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5257 return WINED3DERR_INVALIDCALL;
5260 if(This->stateBlock->streamIsUP) {
5261 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5262 This->stateBlock->streamIsUP = FALSE;
5264 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5266 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5267 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5268 minIndex, NumVertices, startIndex, primCount);
5270 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5271 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5272 idxStride = 2;
5273 } else {
5274 idxStride = 4;
5277 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5278 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5282 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5283 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5285 return WINED3D_OK;
5288 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5289 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5290 UINT VertexStreamZeroStride) {
5291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5292 IWineD3DVertexBuffer *vb;
5294 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5295 debug_d3dprimitivetype(PrimitiveType),
5296 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5298 if(!This->stateBlock->vertexDecl) {
5299 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5300 return WINED3DERR_INVALIDCALL;
5303 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5304 vb = This->stateBlock->streamSource[0];
5305 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5306 if(vb) IWineD3DVertexBuffer_Release(vb);
5307 This->stateBlock->streamOffset[0] = 0;
5308 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5309 This->stateBlock->streamIsUP = TRUE;
5310 This->stateBlock->loadBaseVertexIndex = 0;
5312 /* TODO: Only mark dirty if drawing from a different UP address */
5313 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5315 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5316 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5318 /* MSDN specifies stream zero settings must be set to NULL */
5319 This->stateBlock->streamStride[0] = 0;
5320 This->stateBlock->streamSource[0] = NULL;
5322 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5323 * the new stream sources or use UP drawing again
5325 return WINED3D_OK;
5328 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5329 UINT MinVertexIndex, UINT NumVertices,
5330 UINT PrimitiveCount, CONST void* pIndexData,
5331 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5332 UINT VertexStreamZeroStride) {
5333 int idxStride;
5334 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5335 IWineD3DVertexBuffer *vb;
5336 IWineD3DIndexBuffer *ib;
5338 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5339 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5340 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5341 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5343 if(!This->stateBlock->vertexDecl) {
5344 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5345 return WINED3DERR_INVALIDCALL;
5348 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5349 idxStride = 2;
5350 } else {
5351 idxStride = 4;
5354 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5355 vb = This->stateBlock->streamSource[0];
5356 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5357 if(vb) IWineD3DVertexBuffer_Release(vb);
5358 This->stateBlock->streamIsUP = TRUE;
5359 This->stateBlock->streamOffset[0] = 0;
5360 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5362 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5363 This->stateBlock->baseVertexIndex = 0;
5364 This->stateBlock->loadBaseVertexIndex = 0;
5365 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5366 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5367 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5369 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5371 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5372 This->stateBlock->streamSource[0] = NULL;
5373 This->stateBlock->streamStride[0] = 0;
5374 ib = This->stateBlock->pIndexData;
5375 if(ib) {
5376 IWineD3DIndexBuffer_Release(ib);
5377 This->stateBlock->pIndexData = NULL;
5379 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5380 * SetStreamSource to specify a vertex buffer
5383 return WINED3D_OK;
5386 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5387 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5389 /* Mark the state dirty until we have nicer tracking
5390 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5391 * that value.
5393 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5394 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5395 This->stateBlock->baseVertexIndex = 0;
5396 This->up_strided = DrawPrimStrideData;
5397 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5398 This->up_strided = NULL;
5399 return WINED3D_OK;
5402 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5403 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5404 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5406 /* Mark the state dirty until we have nicer tracking
5407 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5408 * that value.
5410 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5412 This->stateBlock->streamIsUP = TRUE;
5413 This->stateBlock->baseVertexIndex = 0;
5414 This->up_strided = DrawPrimStrideData;
5415 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5416 This->up_strided = NULL;
5417 return WINED3D_OK;
5420 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5421 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5422 * not callable by the app directly no parameter validation checks are needed here.
5424 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5425 WINED3DLOCKED_BOX src;
5426 WINED3DLOCKED_BOX dst;
5427 HRESULT hr;
5428 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5430 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5431 * dirtification to improve loading performance.
5433 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5434 if(FAILED(hr)) return hr;
5435 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5436 if(FAILED(hr)) {
5437 IWineD3DVolume_UnlockBox(pSourceVolume);
5438 return hr;
5441 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5443 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5444 if(FAILED(hr)) {
5445 IWineD3DVolume_UnlockBox(pSourceVolume);
5446 } else {
5447 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5449 return hr;
5452 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5453 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5454 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5455 HRESULT hr = WINED3D_OK;
5456 WINED3DRESOURCETYPE sourceType;
5457 WINED3DRESOURCETYPE destinationType;
5458 int i ,levels;
5460 /* TODO: think about moving the code into IWineD3DBaseTexture */
5462 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5464 /* verify that the source and destination textures aren't NULL */
5465 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5466 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5467 This, pSourceTexture, pDestinationTexture);
5468 hr = WINED3DERR_INVALIDCALL;
5471 if (pSourceTexture == pDestinationTexture) {
5472 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5473 This, pSourceTexture, pDestinationTexture);
5474 hr = WINED3DERR_INVALIDCALL;
5476 /* Verify that the source and destination textures are the same type */
5477 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5478 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5480 if (sourceType != destinationType) {
5481 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5482 This);
5483 hr = WINED3DERR_INVALIDCALL;
5486 /* check that both textures have the identical numbers of levels */
5487 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5488 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5489 hr = WINED3DERR_INVALIDCALL;
5492 if (WINED3D_OK == hr) {
5494 /* Make sure that the destination texture is loaded */
5495 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5497 /* Update every surface level of the texture */
5498 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5500 switch (sourceType) {
5501 case WINED3DRTYPE_TEXTURE:
5503 IWineD3DSurface *srcSurface;
5504 IWineD3DSurface *destSurface;
5506 for (i = 0 ; i < levels ; ++i) {
5507 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5508 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5509 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5510 IWineD3DSurface_Release(srcSurface);
5511 IWineD3DSurface_Release(destSurface);
5512 if (WINED3D_OK != hr) {
5513 WARN("(%p) : Call to update surface failed\n", This);
5514 return hr;
5518 break;
5519 case WINED3DRTYPE_CUBETEXTURE:
5521 IWineD3DSurface *srcSurface;
5522 IWineD3DSurface *destSurface;
5523 WINED3DCUBEMAP_FACES faceType;
5525 for (i = 0 ; i < levels ; ++i) {
5526 /* Update each cube face */
5527 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5528 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5529 if (WINED3D_OK != hr) {
5530 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5531 } else {
5532 TRACE("Got srcSurface %p\n", srcSurface);
5534 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5535 if (WINED3D_OK != hr) {
5536 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5537 } else {
5538 TRACE("Got desrSurface %p\n", destSurface);
5540 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5541 IWineD3DSurface_Release(srcSurface);
5542 IWineD3DSurface_Release(destSurface);
5543 if (WINED3D_OK != hr) {
5544 WARN("(%p) : Call to update surface failed\n", This);
5545 return hr;
5550 break;
5552 case WINED3DRTYPE_VOLUMETEXTURE:
5554 IWineD3DVolume *srcVolume = NULL;
5555 IWineD3DVolume *destVolume = NULL;
5557 for (i = 0 ; i < levels ; ++i) {
5558 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5559 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5560 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5561 IWineD3DVolume_Release(srcVolume);
5562 IWineD3DVolume_Release(destVolume);
5563 if (WINED3D_OK != hr) {
5564 WARN("(%p) : Call to update volume failed\n", This);
5565 return hr;
5569 break;
5571 default:
5572 FIXME("(%p) : Unsupported source and destination type\n", This);
5573 hr = WINED3DERR_INVALIDCALL;
5577 return hr;
5580 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5581 IWineD3DSwapChain *swapChain;
5582 HRESULT hr;
5583 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5584 if(hr == WINED3D_OK) {
5585 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5586 IWineD3DSwapChain_Release(swapChain);
5588 return hr;
5591 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5592 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5593 /* return a sensible default */
5594 *pNumPasses = 1;
5595 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5596 FIXME("(%p) : stub\n", This);
5597 return WINED3D_OK;
5600 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5602 int i;
5604 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5605 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5606 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5607 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5612 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5613 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5614 int j;
5615 UINT NewSize;
5616 PALETTEENTRY **palettes;
5618 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5620 if (PaletteNumber >= MAX_PALETTES) {
5621 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5622 return WINED3DERR_INVALIDCALL;
5625 if (PaletteNumber >= This->NumberOfPalettes) {
5626 NewSize = This->NumberOfPalettes;
5627 do {
5628 NewSize *= 2;
5629 } while(PaletteNumber >= NewSize);
5630 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5631 if (!palettes) {
5632 ERR("Out of memory!\n");
5633 return E_OUTOFMEMORY;
5635 This->palettes = palettes;
5636 This->NumberOfPalettes = NewSize;
5639 if (!This->palettes[PaletteNumber]) {
5640 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5641 if (!This->palettes[PaletteNumber]) {
5642 ERR("Out of memory!\n");
5643 return E_OUTOFMEMORY;
5647 for (j = 0; j < 256; ++j) {
5648 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5649 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5650 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5651 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5653 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5654 TRACE("(%p) : returning\n", This);
5655 return WINED3D_OK;
5658 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5659 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5660 int j;
5661 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5662 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5663 /* What happens in such situation isn't documented; Native seems to silently abort
5664 on such conditions. Return Invalid Call. */
5665 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5666 return WINED3DERR_INVALIDCALL;
5668 for (j = 0; j < 256; ++j) {
5669 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5670 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5671 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5672 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5674 TRACE("(%p) : returning\n", This);
5675 return WINED3D_OK;
5678 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5679 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5680 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5681 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5682 (tested with reference rasterizer). Return Invalid Call. */
5683 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5684 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5685 return WINED3DERR_INVALIDCALL;
5687 /*TODO: stateblocks */
5688 if (This->currentPalette != PaletteNumber) {
5689 This->currentPalette = PaletteNumber;
5690 dirtify_p8_texture_samplers(This);
5692 TRACE("(%p) : returning\n", This);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 if (PaletteNumber == NULL) {
5699 WARN("(%p) : returning Invalid Call\n", This);
5700 return WINED3DERR_INVALIDCALL;
5702 /*TODO: stateblocks */
5703 *PaletteNumber = This->currentPalette;
5704 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5705 return WINED3D_OK;
5708 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 static BOOL showFixmes = TRUE;
5711 if (showFixmes) {
5712 FIXME("(%p) : stub\n", This);
5713 showFixmes = FALSE;
5716 This->softwareVertexProcessing = bSoftware;
5717 return WINED3D_OK;
5721 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5722 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5723 static BOOL showFixmes = TRUE;
5724 if (showFixmes) {
5725 FIXME("(%p) : stub\n", This);
5726 showFixmes = FALSE;
5728 return This->softwareVertexProcessing;
5732 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5733 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5734 IWineD3DSwapChain *swapChain;
5735 HRESULT hr;
5737 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5739 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5740 if(hr == WINED3D_OK){
5741 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5742 IWineD3DSwapChain_Release(swapChain);
5743 }else{
5744 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5746 return hr;
5750 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 static BOOL showfixmes = TRUE;
5753 if(nSegments != 0.0f) {
5754 if( showfixmes) {
5755 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5756 showfixmes = FALSE;
5759 return WINED3D_OK;
5762 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 static BOOL showfixmes = TRUE;
5765 if( showfixmes) {
5766 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5767 showfixmes = FALSE;
5769 return 0.0f;
5772 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5773 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5774 /** TODO: remove casts to IWineD3DSurfaceImpl
5775 * NOTE: move code to surface to accomplish this
5776 ****************************************/
5777 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5778 int srcWidth, srcHeight;
5779 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5780 WINED3DFORMAT destFormat, srcFormat;
5781 UINT destSize;
5782 int srcLeft, destLeft, destTop;
5783 WINED3DPOOL srcPool, destPool;
5784 int offset = 0;
5785 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5786 glDescriptor *glDescription = NULL;
5787 GLenum dummy;
5788 int sampler;
5789 int bpp;
5790 CONVERT_TYPES convert = NO_CONVERSION;
5792 WINED3DSURFACE_DESC winedesc;
5794 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5795 memset(&winedesc, 0, sizeof(winedesc));
5796 winedesc.Width = &srcSurfaceWidth;
5797 winedesc.Height = &srcSurfaceHeight;
5798 winedesc.Pool = &srcPool;
5799 winedesc.Format = &srcFormat;
5801 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5803 winedesc.Width = &destSurfaceWidth;
5804 winedesc.Height = &destSurfaceHeight;
5805 winedesc.Pool = &destPool;
5806 winedesc.Format = &destFormat;
5807 winedesc.Size = &destSize;
5809 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5811 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5812 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5813 return WINED3DERR_INVALIDCALL;
5816 /* This call loads the opengl surface directly, instead of copying the surface to the
5817 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5818 * copy in sysmem and use regular surface loading.
5820 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5821 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5822 if(convert != NO_CONVERSION) {
5823 return IWineD3DSurface_BltFast(pDestinationSurface,
5824 pDestPoint ? pDestPoint->x : 0,
5825 pDestPoint ? pDestPoint->y : 0,
5826 pSourceSurface, (RECT *) pSourceRect, 0);
5829 if (destFormat == WINED3DFMT_UNKNOWN) {
5830 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5831 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5833 /* Get the update surface description */
5834 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5837 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5839 ENTER_GL();
5841 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5842 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5843 checkGLcall("glActiveTextureARB");
5846 /* Make sure the surface is loaded and up to date */
5847 IWineD3DSurface_PreLoad(pDestinationSurface);
5849 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5851 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5852 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5853 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5854 srcLeft = pSourceRect ? pSourceRect->left : 0;
5855 destLeft = pDestPoint ? pDestPoint->x : 0;
5856 destTop = pDestPoint ? pDestPoint->y : 0;
5859 /* This function doesn't support compressed textures
5860 the pitch is just bytesPerPixel * width */
5861 if(srcWidth != srcSurfaceWidth || srcLeft ){
5862 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5863 offset += srcLeft * pSrcSurface->bytesPerPixel;
5864 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5866 /* TODO DXT formats */
5868 if(pSourceRect != NULL && pSourceRect->top != 0){
5869 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5871 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5872 ,This
5873 ,glDescription->level
5874 ,destLeft
5875 ,destTop
5876 ,srcWidth
5877 ,srcHeight
5878 ,glDescription->glFormat
5879 ,glDescription->glType
5880 ,IWineD3DSurface_GetData(pSourceSurface)
5883 /* Sanity check */
5884 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5886 /* need to lock the surface to get the data */
5887 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5890 /* TODO: Cube and volume support */
5891 if(rowoffset != 0){
5892 /* not a whole row so we have to do it a line at a time */
5893 int j;
5895 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5896 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5898 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5900 glTexSubImage2D(glDescription->target
5901 ,glDescription->level
5902 ,destLeft
5904 ,srcWidth
5906 ,glDescription->glFormat
5907 ,glDescription->glType
5908 ,data /* could be quicker using */
5910 data += rowoffset;
5913 } else { /* Full width, so just write out the whole texture */
5915 if (WINED3DFMT_DXT1 == destFormat ||
5916 WINED3DFMT_DXT2 == destFormat ||
5917 WINED3DFMT_DXT3 == destFormat ||
5918 WINED3DFMT_DXT4 == destFormat ||
5919 WINED3DFMT_DXT5 == destFormat) {
5920 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5921 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5922 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5923 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5924 } if (destFormat != srcFormat) {
5925 FIXME("Updating mixed format compressed texture is not curretly support\n");
5926 } else {
5927 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5928 glDescription->level,
5929 glDescription->glFormatInternal,
5930 srcWidth,
5931 srcHeight,
5933 destSize,
5934 IWineD3DSurface_GetData(pSourceSurface));
5936 } else {
5937 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5941 } else {
5942 glTexSubImage2D(glDescription->target
5943 ,glDescription->level
5944 ,destLeft
5945 ,destTop
5946 ,srcWidth
5947 ,srcHeight
5948 ,glDescription->glFormat
5949 ,glDescription->glType
5950 ,IWineD3DSurface_GetData(pSourceSurface)
5954 checkGLcall("glTexSubImage2D");
5956 LEAVE_GL();
5958 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5959 sampler = This->rev_tex_unit_map[0];
5960 if (sampler != -1) {
5961 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5964 return WINED3D_OK;
5967 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5968 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5969 struct WineD3DRectPatch *patch;
5970 unsigned int i;
5971 struct list *e;
5972 BOOL found;
5973 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5975 if(!(Handle || pRectPatchInfo)) {
5976 /* TODO: Write a test for the return value, thus the FIXME */
5977 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5978 return WINED3DERR_INVALIDCALL;
5981 if(Handle) {
5982 i = PATCHMAP_HASHFUNC(Handle);
5983 found = FALSE;
5984 LIST_FOR_EACH(e, &This->patches[i]) {
5985 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
5986 if(patch->Handle == Handle) {
5987 found = TRUE;
5988 break;
5992 if(!found) {
5993 TRACE("Patch does not exist. Creating a new one\n");
5994 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
5995 patch->Handle = Handle;
5996 list_add_head(&This->patches[i], &patch->entry);
5997 } else {
5998 TRACE("Found existing patch %p\n", patch);
6000 } else {
6001 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6002 * attributes we have to tesselate, read back, and draw. This needs a patch
6003 * management structure instance. Create one.
6005 * A possible improvement is to check if a vertex shader is used, and if not directly
6006 * draw the patch.
6008 FIXME("Drawing an uncached patch. This is slow\n");
6009 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6012 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6013 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6014 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6015 HRESULT hr;
6016 TRACE("Tesselation density or patch info changed, retesselating\n");
6018 if(pRectPatchInfo) {
6019 patch->RectPatchInfo = *pRectPatchInfo;
6021 patch->numSegs[0] = pNumSegs[0];
6022 patch->numSegs[1] = pNumSegs[1];
6023 patch->numSegs[2] = pNumSegs[2];
6024 patch->numSegs[3] = pNumSegs[3];
6026 hr = tesselate_rectpatch(This, patch);
6027 if(FAILED(hr)) {
6028 WARN("Patch tesselation failed\n");
6030 /* Do not release the handle to store the params of the patch */
6031 if(!Handle) {
6032 HeapFree(GetProcessHeap(), 0, patch);
6034 return hr;
6038 This->currentPatch = patch;
6039 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6040 This->currentPatch = NULL;
6042 /* Destroy uncached patches */
6043 if(!Handle) {
6044 HeapFree(GetProcessHeap(), 0, patch->mem);
6045 HeapFree(GetProcessHeap(), 0, patch);
6047 return WINED3D_OK;
6050 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6052 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6053 FIXME("(%p) : Stub\n", This);
6054 return WINED3D_OK;
6057 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6059 int i;
6060 struct WineD3DRectPatch *patch;
6061 struct list *e;
6062 TRACE("(%p) Handle(%d)\n", This, Handle);
6064 i = PATCHMAP_HASHFUNC(Handle);
6065 LIST_FOR_EACH(e, &This->patches[i]) {
6066 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6067 if(patch->Handle == Handle) {
6068 TRACE("Deleting patch %p\n", patch);
6069 list_remove(&patch->entry);
6070 HeapFree(GetProcessHeap(), 0, patch->mem);
6071 HeapFree(GetProcessHeap(), 0, patch);
6072 return WINED3D_OK;
6076 /* TODO: Write a test for the return value */
6077 FIXME("Attempt to destroy nonexistent patch\n");
6078 return WINED3DERR_INVALIDCALL;
6081 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6082 HRESULT hr;
6083 IWineD3DSwapChain *swapchain;
6085 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6086 if (SUCCEEDED(hr)) {
6087 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6088 return swapchain;
6091 return NULL;
6094 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6097 if (!*fbo) {
6098 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6099 checkGLcall("glGenFramebuffersEXT()");
6101 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6102 checkGLcall("glBindFramebuffer()");
6105 /* TODO: Handle stencil attachments */
6106 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6107 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6109 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6110 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6111 checkGLcall("glFramebufferRenderbufferEXT()");
6112 } else {
6113 IWineD3DBaseTextureImpl *texture_impl;
6114 GLenum texttarget, target;
6115 GLint old_binding = 0;
6117 texttarget = depth_stencil_impl->glDescription.target;
6118 if(texttarget == GL_TEXTURE_2D) {
6119 target = GL_TEXTURE_2D;
6120 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6121 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6122 target = GL_TEXTURE_RECTANGLE_ARB;
6123 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6124 } else {
6125 target = GL_TEXTURE_CUBE_MAP_ARB;
6126 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6129 IWineD3DSurface_PreLoad(depth_stencil);
6131 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6132 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6133 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6134 glBindTexture(target, old_binding);
6136 /* Update base texture states array */
6137 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6138 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6139 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6140 if (texture_impl->baseTexture.bindCount) {
6141 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6144 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6147 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6148 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6149 checkGLcall("glFramebufferTexture2DEXT()");
6153 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6154 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6155 IWineD3DBaseTextureImpl *texture_impl;
6156 GLenum texttarget, target;
6157 GLint old_binding;
6159 texttarget = surface_impl->glDescription.target;
6160 if(texttarget == GL_TEXTURE_2D) {
6161 target = GL_TEXTURE_2D;
6162 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6163 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6164 target = GL_TEXTURE_RECTANGLE_ARB;
6165 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6166 } else {
6167 target = GL_TEXTURE_CUBE_MAP_ARB;
6168 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6171 IWineD3DSurface_PreLoad(surface);
6173 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6174 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6175 glBindTexture(target, old_binding);
6177 /* Update base texture states array */
6178 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6179 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6180 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6181 if (texture_impl->baseTexture.bindCount) {
6182 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6185 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6188 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6189 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6191 checkGLcall("attach_surface_fbo");
6194 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6195 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6196 IWineD3DSwapChain *swapchain;
6198 swapchain = get_swapchain(surface);
6199 if (swapchain) {
6200 GLenum buffer;
6202 TRACE("Surface %p is onscreen\n", surface);
6204 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6205 ENTER_GL();
6206 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6207 buffer = surface_get_gl_buffer(surface, swapchain);
6208 glDrawBuffer(buffer);
6209 checkGLcall("glDrawBuffer()");
6210 } else {
6211 TRACE("Surface %p is offscreen\n", surface);
6213 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6214 ENTER_GL();
6215 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6216 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6217 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6218 checkGLcall("glFramebufferRenderbufferEXT");
6221 if (rect) {
6222 glEnable(GL_SCISSOR_TEST);
6223 if(!swapchain) {
6224 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6225 } else {
6226 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6227 rect->x2 - rect->x1, rect->y2 - rect->y1);
6229 checkGLcall("glScissor");
6230 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6231 } else {
6232 glDisable(GL_SCISSOR_TEST);
6234 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6236 glDisable(GL_BLEND);
6237 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6239 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6240 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6242 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6243 glClear(GL_COLOR_BUFFER_BIT);
6244 checkGLcall("glClear");
6246 if (This->render_offscreen) {
6247 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6248 } else {
6249 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6250 checkGLcall("glBindFramebuffer()");
6253 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6254 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6255 glDrawBuffer(GL_BACK);
6256 checkGLcall("glDrawBuffer()");
6259 LEAVE_GL();
6262 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6263 unsigned int r, g, b, a;
6264 DWORD ret;
6266 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6267 destfmt == WINED3DFMT_R8G8B8)
6268 return color;
6270 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6272 a = (color & 0xff000000) >> 24;
6273 r = (color & 0x00ff0000) >> 16;
6274 g = (color & 0x0000ff00) >> 8;
6275 b = (color & 0x000000ff) >> 0;
6277 switch(destfmt)
6279 case WINED3DFMT_R5G6B5:
6280 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6281 r = (r * 32) / 256;
6282 g = (g * 64) / 256;
6283 b = (b * 32) / 256;
6284 ret = r << 11;
6285 ret |= g << 5;
6286 ret |= b;
6287 TRACE("Returning %08x\n", ret);
6288 return ret;
6290 case WINED3DFMT_X1R5G5B5:
6291 case WINED3DFMT_A1R5G5B5:
6292 a = (a * 2) / 256;
6293 r = (r * 32) / 256;
6294 g = (g * 32) / 256;
6295 b = (b * 32) / 256;
6296 ret = a << 15;
6297 ret |= r << 10;
6298 ret |= g << 5;
6299 ret |= b << 0;
6300 TRACE("Returning %08x\n", ret);
6301 return ret;
6303 case WINED3DFMT_A8:
6304 TRACE("Returning %08x\n", a);
6305 return a;
6307 case WINED3DFMT_X4R4G4B4:
6308 case WINED3DFMT_A4R4G4B4:
6309 a = (a * 16) / 256;
6310 r = (r * 16) / 256;
6311 g = (g * 16) / 256;
6312 b = (b * 16) / 256;
6313 ret = a << 12;
6314 ret |= r << 8;
6315 ret |= g << 4;
6316 ret |= b << 0;
6317 TRACE("Returning %08x\n", ret);
6318 return ret;
6320 case WINED3DFMT_R3G3B2:
6321 r = (r * 8) / 256;
6322 g = (g * 8) / 256;
6323 b = (b * 4) / 256;
6324 ret = r << 5;
6325 ret |= g << 2;
6326 ret |= b << 0;
6327 TRACE("Returning %08x\n", ret);
6328 return ret;
6330 case WINED3DFMT_X8B8G8R8:
6331 case WINED3DFMT_A8B8G8R8:
6332 ret = a << 24;
6333 ret |= b << 16;
6334 ret |= g << 8;
6335 ret |= r << 0;
6336 TRACE("Returning %08x\n", ret);
6337 return ret;
6339 case WINED3DFMT_A2R10G10B10:
6340 a = (a * 4) / 256;
6341 r = (r * 1024) / 256;
6342 g = (g * 1024) / 256;
6343 b = (b * 1024) / 256;
6344 ret = a << 30;
6345 ret |= r << 20;
6346 ret |= g << 10;
6347 ret |= b << 0;
6348 TRACE("Returning %08x\n", ret);
6349 return ret;
6351 case WINED3DFMT_A2B10G10R10:
6352 a = (a * 4) / 256;
6353 r = (r * 1024) / 256;
6354 g = (g * 1024) / 256;
6355 b = (b * 1024) / 256;
6356 ret = a << 30;
6357 ret |= b << 20;
6358 ret |= g << 10;
6359 ret |= r << 0;
6360 TRACE("Returning %08x\n", ret);
6361 return ret;
6363 default:
6364 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6365 return 0;
6369 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6370 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6371 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6372 WINEDDBLTFX BltFx;
6373 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6375 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6376 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6377 return WINED3DERR_INVALIDCALL;
6380 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6381 color_fill_fbo(iface, pSurface, pRect, color);
6382 return WINED3D_OK;
6383 } else {
6384 /* Just forward this to the DirectDraw blitting engine */
6385 memset(&BltFx, 0, sizeof(BltFx));
6386 BltFx.dwSize = sizeof(BltFx);
6387 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6388 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6392 /* rendertarget and depth stencil functions */
6393 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6394 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6396 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6397 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6398 return WINED3DERR_INVALIDCALL;
6401 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6402 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6403 /* Note inc ref on returned surface */
6404 if(*ppRenderTarget != NULL)
6405 IWineD3DSurface_AddRef(*ppRenderTarget);
6406 return WINED3D_OK;
6409 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6410 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6411 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6412 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6413 IWineD3DSwapChainImpl *Swapchain;
6414 HRESULT hr;
6416 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6418 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6419 if(hr != WINED3D_OK) {
6420 ERR("Can't get the swapchain\n");
6421 return hr;
6424 /* Make sure to release the swapchain */
6425 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6427 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6428 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6429 return WINED3DERR_INVALIDCALL;
6431 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6432 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6433 return WINED3DERR_INVALIDCALL;
6436 if(Swapchain->frontBuffer != Front) {
6437 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6439 if(Swapchain->frontBuffer)
6440 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6441 Swapchain->frontBuffer = Front;
6443 if(Swapchain->frontBuffer) {
6444 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6448 if(Back && !Swapchain->backBuffer) {
6449 /* We need memory for the back buffer array - only one back buffer this way */
6450 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6451 if(!Swapchain->backBuffer) {
6452 ERR("Out of memory\n");
6453 return E_OUTOFMEMORY;
6457 if(Swapchain->backBuffer[0] != Back) {
6458 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6460 /* What to do about the context here in the case of multithreading? Not sure.
6461 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6463 ENTER_GL();
6464 if(!Swapchain->backBuffer[0]) {
6465 /* GL was told to draw to the front buffer at creation,
6466 * undo that
6468 glDrawBuffer(GL_BACK);
6469 checkGLcall("glDrawBuffer(GL_BACK)");
6470 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6471 Swapchain->presentParms.BackBufferCount = 1;
6472 } else if (!Back) {
6473 /* That makes problems - disable for now */
6474 /* glDrawBuffer(GL_FRONT); */
6475 checkGLcall("glDrawBuffer(GL_FRONT)");
6476 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6477 Swapchain->presentParms.BackBufferCount = 0;
6479 LEAVE_GL();
6481 if(Swapchain->backBuffer[0])
6482 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6483 Swapchain->backBuffer[0] = Back;
6485 if(Swapchain->backBuffer[0]) {
6486 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6487 } else {
6488 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6489 Swapchain->backBuffer = NULL;
6494 return WINED3D_OK;
6497 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6498 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6499 *ppZStencilSurface = This->stencilBufferTarget;
6500 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6502 if(*ppZStencilSurface != NULL) {
6503 /* Note inc ref on returned surface */
6504 IWineD3DSurface_AddRef(*ppZStencilSurface);
6505 return WINED3D_OK;
6506 } else {
6507 return WINED3DERR_NOTFOUND;
6511 /* TODO: Handle stencil attachments */
6512 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6513 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6515 TRACE("Set depth stencil to %p\n", depth_stencil);
6517 if (depth_stencil) {
6518 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6519 } else {
6520 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6521 checkGLcall("glFramebufferTexture2DEXT()");
6525 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6526 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6528 TRACE("Set render target %u to %p\n", idx, render_target);
6530 if (render_target) {
6531 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6532 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6533 } else {
6534 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6535 checkGLcall("glFramebufferTexture2DEXT()");
6537 This->draw_buffers[idx] = GL_NONE;
6541 static void check_fbo_status(IWineD3DDevice *iface) {
6542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6543 GLenum status;
6545 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6546 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6547 TRACE("FBO complete\n");
6548 } else {
6549 IWineD3DSurfaceImpl *attachment;
6550 int i;
6551 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6553 /* Dump the FBO attachments */
6554 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6555 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6556 if (attachment) {
6557 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6558 attachment->pow2Width, attachment->pow2Height);
6561 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6562 if (attachment) {
6563 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6564 attachment->pow2Width, attachment->pow2Height);
6569 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6571 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6572 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6574 if (!ds_impl) return FALSE;
6576 if (ds_impl->current_renderbuffer) {
6577 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6578 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6581 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6582 rt_impl->pow2Height != ds_impl->pow2Height);
6585 void apply_fbo_state(IWineD3DDevice *iface) {
6586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6587 unsigned int i;
6589 if (This->render_offscreen) {
6590 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6592 /* Apply render targets */
6593 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6594 IWineD3DSurface *render_target = This->render_targets[i];
6595 if (This->fbo_color_attachments[i] != render_target) {
6596 set_render_target_fbo(iface, i, render_target);
6597 This->fbo_color_attachments[i] = render_target;
6601 /* Apply depth targets */
6602 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6603 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6604 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6606 if (This->stencilBufferTarget) {
6607 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6609 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6610 This->fbo_depth_attachment = This->stencilBufferTarget;
6612 } else {
6613 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6616 check_fbo_status(iface);
6619 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6620 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6621 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6622 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6623 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6624 GLenum gl_filter;
6625 POINT offset = {0, 0};
6627 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6628 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6629 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6630 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6632 switch (filter) {
6633 case WINED3DTEXF_LINEAR:
6634 gl_filter = GL_LINEAR;
6635 break;
6637 default:
6638 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6639 case WINED3DTEXF_NONE:
6640 case WINED3DTEXF_POINT:
6641 gl_filter = GL_NEAREST;
6642 break;
6645 /* Attach src surface to src fbo */
6646 src_swapchain = get_swapchain(src_surface);
6647 if (src_swapchain) {
6648 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6650 TRACE("Source surface %p is onscreen\n", src_surface);
6651 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6652 /* Make sure the drawable is up to date. In the offscreen case
6653 * attach_surface_fbo() implicitly takes care of this. */
6654 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6656 if(buffer == GL_FRONT) {
6657 RECT windowsize;
6658 UINT h;
6659 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6660 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6661 h = windowsize.bottom - windowsize.top;
6662 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6663 src_rect->y1 = offset.y + h - src_rect->y1;
6664 src_rect->y2 = offset.y + h - src_rect->y2;
6665 } else {
6666 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6667 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6670 ENTER_GL();
6671 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6672 glReadBuffer(buffer);
6673 checkGLcall("glReadBuffer()");
6674 } else {
6675 TRACE("Source surface %p is offscreen\n", src_surface);
6676 ENTER_GL();
6677 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6678 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6679 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6680 checkGLcall("glReadBuffer()");
6681 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6682 checkGLcall("glFramebufferRenderbufferEXT");
6684 LEAVE_GL();
6686 /* Attach dst surface to dst fbo */
6687 dst_swapchain = get_swapchain(dst_surface);
6688 if (dst_swapchain) {
6689 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6691 TRACE("Destination surface %p is onscreen\n", dst_surface);
6692 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6693 /* Make sure the drawable is up to date. In the offscreen case
6694 * attach_surface_fbo() implicitly takes care of this. */
6695 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6697 if(buffer == GL_FRONT) {
6698 RECT windowsize;
6699 UINT h;
6700 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6701 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6702 h = windowsize.bottom - windowsize.top;
6703 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6704 dst_rect->y1 = offset.y + h - dst_rect->y1;
6705 dst_rect->y2 = offset.y + h - dst_rect->y2;
6706 } else {
6707 /* Screen coords = window coords, surface height = window height */
6708 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6709 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6712 ENTER_GL();
6713 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6714 glDrawBuffer(buffer);
6715 checkGLcall("glDrawBuffer()");
6716 } else {
6717 TRACE("Destination surface %p is offscreen\n", dst_surface);
6719 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6720 if(!src_swapchain) {
6721 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6724 ENTER_GL();
6725 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6726 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6727 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6728 checkGLcall("glDrawBuffer()");
6729 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6730 checkGLcall("glFramebufferRenderbufferEXT");
6732 glDisable(GL_SCISSOR_TEST);
6733 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6735 if (flip) {
6736 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6737 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6738 checkGLcall("glBlitFramebuffer()");
6739 } else {
6740 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6741 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6742 checkGLcall("glBlitFramebuffer()");
6745 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6747 if (This->render_offscreen) {
6748 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6749 } else {
6750 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6751 checkGLcall("glBindFramebuffer()");
6754 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6755 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6756 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6757 glDrawBuffer(GL_BACK);
6758 checkGLcall("glDrawBuffer()");
6760 LEAVE_GL();
6763 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6764 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6765 WINED3DVIEWPORT viewport;
6767 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6769 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6770 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6771 This, RenderTargetIndex, GL_LIMITS(buffers));
6772 return WINED3DERR_INVALIDCALL;
6775 /* MSDN says that null disables the render target
6776 but a device must always be associated with a render target
6777 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6779 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6780 FIXME("Trying to set render target 0 to NULL\n");
6781 return WINED3DERR_INVALIDCALL;
6783 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6784 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);
6785 return WINED3DERR_INVALIDCALL;
6788 /* If we are trying to set what we already have, don't bother */
6789 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6790 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6791 return WINED3D_OK;
6793 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6794 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6795 This->render_targets[RenderTargetIndex] = pRenderTarget;
6797 /* Render target 0 is special */
6798 if(RenderTargetIndex == 0) {
6799 /* Finally, reset the viewport as the MSDN states. */
6800 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6801 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6802 viewport.X = 0;
6803 viewport.Y = 0;
6804 viewport.MaxZ = 1.0f;
6805 viewport.MinZ = 0.0f;
6806 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6807 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6808 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6810 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6812 return WINED3D_OK;
6815 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6817 HRESULT hr = WINED3D_OK;
6818 IWineD3DSurface *tmp;
6820 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6822 if (pNewZStencil == This->stencilBufferTarget) {
6823 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6824 } else {
6825 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6826 * depending on the renter target implementation being used.
6827 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6828 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6829 * stencil buffer and incur an extra memory overhead
6830 ******************************************************/
6832 if (This->stencilBufferTarget) {
6833 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6834 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6835 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6838 tmp = This->stencilBufferTarget;
6839 This->stencilBufferTarget = pNewZStencil;
6840 /* should we be calling the parent or the wined3d surface? */
6841 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6842 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6843 hr = WINED3D_OK;
6845 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6846 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6847 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6848 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6853 return hr;
6856 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6857 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6858 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6859 /* TODO: the use of Impl is deprecated. */
6860 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6861 WINED3DLOCKED_RECT lockedRect;
6863 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6865 /* some basic validation checks */
6866 if(This->cursorTexture) {
6867 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6868 ENTER_GL();
6869 glDeleteTextures(1, &This->cursorTexture);
6870 LEAVE_GL();
6871 This->cursorTexture = 0;
6874 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6875 This->haveHardwareCursor = TRUE;
6876 else
6877 This->haveHardwareCursor = FALSE;
6879 if(pCursorBitmap) {
6880 WINED3DLOCKED_RECT rect;
6882 /* MSDN: Cursor must be A8R8G8B8 */
6883 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6884 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6885 return WINED3DERR_INVALIDCALL;
6888 /* MSDN: Cursor must be smaller than the display mode */
6889 if(pSur->currentDesc.Width > This->ddraw_width ||
6890 pSur->currentDesc.Height > This->ddraw_height) {
6891 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);
6892 return WINED3DERR_INVALIDCALL;
6895 if (!This->haveHardwareCursor) {
6896 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6898 /* Do not store the surface's pointer because the application may
6899 * release it after setting the cursor image. Windows doesn't
6900 * addref the set surface, so we can't do this either without
6901 * creating circular refcount dependencies. Copy out the gl texture
6902 * instead.
6904 This->cursorWidth = pSur->currentDesc.Width;
6905 This->cursorHeight = pSur->currentDesc.Height;
6906 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6908 const GlPixelFormatDesc *glDesc;
6909 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6910 char *mem, *bits = (char *)rect.pBits;
6911 GLint intfmt = glDesc->glInternal;
6912 GLint format = glDesc->glFormat;
6913 GLint type = glDesc->glType;
6914 INT height = This->cursorHeight;
6915 INT width = This->cursorWidth;
6916 INT bpp = tableEntry->bpp;
6917 INT i, sampler;
6919 /* Reformat the texture memory (pitch and width can be
6920 * different) */
6921 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6922 for(i = 0; i < height; i++)
6923 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6924 IWineD3DSurface_UnlockRect(pCursorBitmap);
6925 ENTER_GL();
6927 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6928 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6929 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6932 /* Make sure that a proper texture unit is selected */
6933 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6934 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6935 checkGLcall("glActiveTextureARB");
6937 sampler = This->rev_tex_unit_map[0];
6938 if (sampler != -1) {
6939 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6941 /* Create a new cursor texture */
6942 glGenTextures(1, &This->cursorTexture);
6943 checkGLcall("glGenTextures");
6944 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6945 checkGLcall("glBindTexture");
6946 /* Copy the bitmap memory into the cursor texture */
6947 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6948 HeapFree(GetProcessHeap(), 0, mem);
6949 checkGLcall("glTexImage2D");
6951 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6952 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6953 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6956 LEAVE_GL();
6958 else
6960 FIXME("A cursor texture was not returned.\n");
6961 This->cursorTexture = 0;
6964 else
6966 /* Draw a hardware cursor */
6967 ICONINFO cursorInfo;
6968 HCURSOR cursor;
6969 /* Create and clear maskBits because it is not needed for
6970 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6971 * chunks. */
6972 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6973 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6974 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6975 WINED3DLOCK_NO_DIRTY_UPDATE |
6976 WINED3DLOCK_READONLY
6978 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6979 pSur->currentDesc.Height);
6981 cursorInfo.fIcon = FALSE;
6982 cursorInfo.xHotspot = XHotSpot;
6983 cursorInfo.yHotspot = YHotSpot;
6984 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
6985 pSur->currentDesc.Height, 1,
6986 1, &maskBits);
6987 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
6988 pSur->currentDesc.Height, 1,
6989 32, lockedRect.pBits);
6990 IWineD3DSurface_UnlockRect(pCursorBitmap);
6991 /* Create our cursor and clean up. */
6992 cursor = CreateIconIndirect(&cursorInfo);
6993 SetCursor(cursor);
6994 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
6995 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
6996 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
6997 This->hardwareCursor = cursor;
6998 HeapFree(GetProcessHeap(), 0, maskBits);
7002 This->xHotSpot = XHotSpot;
7003 This->yHotSpot = YHotSpot;
7004 return WINED3D_OK;
7007 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7008 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7009 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7011 This->xScreenSpace = XScreenSpace;
7012 This->yScreenSpace = YScreenSpace;
7014 return;
7018 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7020 BOOL oldVisible = This->bCursorVisible;
7021 POINT pt;
7023 TRACE("(%p) : visible(%d)\n", This, bShow);
7026 * When ShowCursor is first called it should make the cursor appear at the OS's last
7027 * known cursor position. Because of this, some applications just repetitively call
7028 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7030 GetCursorPos(&pt);
7031 This->xScreenSpace = pt.x;
7032 This->yScreenSpace = pt.y;
7034 if (This->haveHardwareCursor) {
7035 This->bCursorVisible = bShow;
7036 if (bShow)
7037 SetCursor(This->hardwareCursor);
7038 else
7039 SetCursor(NULL);
7041 else
7043 if (This->cursorTexture)
7044 This->bCursorVisible = bShow;
7047 return oldVisible;
7050 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7051 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7052 IWineD3DResourceImpl *resource;
7053 TRACE("(%p) : state (%u)\n", This, This->state);
7055 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7056 switch (This->state) {
7057 case WINED3D_OK:
7058 return WINED3D_OK;
7059 case WINED3DERR_DEVICELOST:
7061 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7062 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7063 return WINED3DERR_DEVICENOTRESET;
7065 return WINED3DERR_DEVICELOST;
7067 case WINED3DERR_DRIVERINTERNALERROR:
7068 return WINED3DERR_DRIVERINTERNALERROR;
7071 /* Unknown state */
7072 return WINED3DERR_DRIVERINTERNALERROR;
7076 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7077 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7078 /** FIXME: Resource tracking needs to be done,
7079 * The closes we can do to this is set the priorities of all managed textures low
7080 * and then reset them.
7081 ***********************************************************/
7082 FIXME("(%p) : stub\n", This);
7083 return WINED3D_OK;
7086 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7087 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7089 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7090 if(surface->Flags & SFLAG_DIBSECTION) {
7091 /* Release the DC */
7092 SelectObject(surface->hDC, surface->dib.holdbitmap);
7093 DeleteDC(surface->hDC);
7094 /* Release the DIB section */
7095 DeleteObject(surface->dib.DIBsection);
7096 surface->dib.bitmap_data = NULL;
7097 surface->resource.allocatedMemory = NULL;
7098 surface->Flags &= ~SFLAG_DIBSECTION;
7100 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7101 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7102 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7103 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7104 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7105 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7106 } else {
7107 surface->pow2Width = surface->pow2Height = 1;
7108 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7109 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7111 surface->glRect.left = 0;
7112 surface->glRect.top = 0;
7113 surface->glRect.right = surface->pow2Width;
7114 surface->glRect.bottom = surface->pow2Height;
7116 if(surface->glDescription.textureName) {
7117 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7118 ENTER_GL();
7119 glDeleteTextures(1, &surface->glDescription.textureName);
7120 LEAVE_GL();
7121 surface->glDescription.textureName = 0;
7122 surface->Flags &= ~SFLAG_CLIENT;
7124 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7125 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7126 surface->Flags |= SFLAG_NONPOW2;
7127 } else {
7128 surface->Flags &= ~SFLAG_NONPOW2;
7130 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7131 surface->resource.allocatedMemory = NULL;
7132 surface->resource.heapMemory = NULL;
7133 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7134 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7135 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7136 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7137 } else {
7138 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7142 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7143 TRACE("Unloading resource %p\n", resource);
7144 IWineD3DResource_UnLoad(resource);
7145 IWineD3DResource_Release(resource);
7146 return S_OK;
7149 static void reset_fbo_state(IWineD3DDevice *iface) {
7150 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7151 unsigned int i;
7153 ENTER_GL();
7154 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7155 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7157 if (This->fbo) {
7158 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7159 This->fbo = 0;
7161 if (This->src_fbo) {
7162 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7163 This->src_fbo = 0;
7165 if (This->dst_fbo) {
7166 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7167 This->dst_fbo = 0;
7169 checkGLcall("Tear down FBOs\n");
7170 LEAVE_GL();
7172 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7173 This->fbo_color_attachments[i] = NULL;
7175 This->fbo_depth_attachment = NULL;
7178 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7179 UINT i, count;
7180 WINED3DDISPLAYMODE m;
7181 HRESULT hr;
7183 /* All Windowed modes are supported, as is leaving the current mode */
7184 if(pp->Windowed) return TRUE;
7185 if(!pp->BackBufferWidth) return TRUE;
7186 if(!pp->BackBufferHeight) return TRUE;
7188 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7189 for(i = 0; i < count; i++) {
7190 memset(&m, 0, sizeof(m));
7191 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7192 if(FAILED(hr)) {
7193 ERR("EnumAdapterModes failed\n");
7195 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7196 /* Mode found, it is supported */
7197 return TRUE;
7200 /* Mode not found -> not supported */
7201 return FALSE;
7204 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7205 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7206 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7207 UINT i;
7208 IWineD3DBaseShaderImpl *shader;
7210 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7211 reset_fbo_state((IWineD3DDevice *) This);
7214 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7215 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7216 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7219 ENTER_GL();
7220 if(This->depth_blt_texture) {
7221 glDeleteTextures(1, &This->depth_blt_texture);
7222 This->depth_blt_texture = 0;
7224 if (This->depth_blt_rb) {
7225 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7226 This->depth_blt_rb = 0;
7227 This->depth_blt_rb_w = 0;
7228 This->depth_blt_rb_h = 0;
7230 This->blitter->free_private(iface);
7231 This->frag_pipe->free_private(iface);
7232 This->shader_backend->shader_free_private(iface);
7234 for (i = 0; i < GL_LIMITS(textures); i++) {
7235 /* Textures are recreated below */
7236 glDeleteTextures(1, &This->dummyTextureName[i]);
7237 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7238 This->dummyTextureName[i] = 0;
7240 LEAVE_GL();
7242 while(This->numContexts) {
7243 DestroyContext(This, This->contexts[0]);
7245 This->activeContext = NULL;
7246 HeapFree(GetProcessHeap(), 0, swapchain->context);
7247 swapchain->context = NULL;
7248 swapchain->num_contexts = 0;
7251 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7252 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7253 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7254 HRESULT hr;
7255 IWineD3DSurfaceImpl *target;
7257 /* Recreate the primary swapchain's context */
7258 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7259 if(swapchain->backBuffer) {
7260 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7261 } else {
7262 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7264 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7265 &swapchain->presentParms);
7266 swapchain->num_contexts = 1;
7267 This->activeContext = swapchain->context[0];
7269 create_dummy_textures(This);
7271 hr = This->shader_backend->shader_alloc_private(iface);
7272 if(FAILED(hr)) {
7273 ERR("Failed to recreate shader private data\n");
7274 goto err_out;
7276 hr = This->frag_pipe->alloc_private(iface);
7277 if(FAILED(hr)) {
7278 TRACE("Fragment pipeline private data couldn't be allocated\n");
7279 goto err_out;
7281 hr = This->blitter->alloc_private(iface);
7282 if(FAILED(hr)) {
7283 TRACE("Blitter private data couldn't be allocated\n");
7284 goto err_out;
7287 return WINED3D_OK;
7289 err_out:
7290 This->blitter->free_private(iface);
7291 This->frag_pipe->free_private(iface);
7292 This->shader_backend->shader_free_private(iface);
7293 return hr;
7296 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7297 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7298 IWineD3DSwapChainImpl *swapchain;
7299 HRESULT hr;
7300 BOOL DisplayModeChanged = FALSE;
7301 WINED3DDISPLAYMODE mode;
7302 TRACE("(%p)\n", This);
7304 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7305 if(FAILED(hr)) {
7306 ERR("Failed to get the first implicit swapchain\n");
7307 return hr;
7310 if(!is_display_mode_supported(This, pPresentationParameters)) {
7311 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7312 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7313 pPresentationParameters->BackBufferHeight);
7314 return WINED3DERR_INVALIDCALL;
7317 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7318 * on an existing gl context, so there's no real need for recreation.
7320 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7322 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7324 TRACE("New params:\n");
7325 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7326 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7327 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7328 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7329 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7330 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7331 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7332 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7333 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7334 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7335 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7336 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7337 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7339 /* No special treatment of these parameters. Just store them */
7340 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7341 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7342 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7343 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7345 /* What to do about these? */
7346 if(pPresentationParameters->BackBufferCount != 0 &&
7347 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7348 ERR("Cannot change the back buffer count yet\n");
7350 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7351 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7352 ERR("Cannot change the back buffer format yet\n");
7354 if(pPresentationParameters->hDeviceWindow != NULL &&
7355 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7356 ERR("Cannot change the device window yet\n");
7358 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7359 ERR("What do do about a changed auto depth stencil parameter?\n");
7362 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7364 if(pPresentationParameters->Windowed) {
7365 mode.Width = swapchain->orig_width;
7366 mode.Height = swapchain->orig_height;
7367 mode.RefreshRate = 0;
7368 mode.Format = swapchain->presentParms.BackBufferFormat;
7369 } else {
7370 mode.Width = pPresentationParameters->BackBufferWidth;
7371 mode.Height = pPresentationParameters->BackBufferHeight;
7372 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7373 mode.Format = swapchain->presentParms.BackBufferFormat;
7376 /* Should Width == 800 && Height == 0 set 800x600? */
7377 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7378 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7379 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7381 WINED3DVIEWPORT vp;
7382 int i;
7384 vp.X = 0;
7385 vp.Y = 0;
7386 vp.Width = pPresentationParameters->BackBufferWidth;
7387 vp.Height = pPresentationParameters->BackBufferHeight;
7388 vp.MinZ = 0;
7389 vp.MaxZ = 1;
7391 if(!pPresentationParameters->Windowed) {
7392 DisplayModeChanged = TRUE;
7394 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7395 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7397 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7398 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7399 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7401 if(This->auto_depth_stencil_buffer) {
7402 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7406 /* Now set the new viewport */
7407 IWineD3DDevice_SetViewport(iface, &vp);
7410 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7411 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7412 DisplayModeChanged) {
7414 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7416 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7417 if(swapchain->presentParms.Windowed) {
7418 /* switch from windowed to fs */
7419 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7420 pPresentationParameters->BackBufferWidth,
7421 pPresentationParameters->BackBufferHeight);
7422 } else {
7423 /* Fullscreen -> fullscreen mode change */
7424 MoveWindow(swapchain->win_handle, 0, 0,
7425 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7426 TRUE);
7428 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7429 /* Fullscreen -> windowed switch */
7430 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7432 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7433 } else if(!pPresentationParameters->Windowed) {
7434 DWORD style = This->style, exStyle = This->exStyle;
7435 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7436 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7437 * Reset to clear up their mess. Guild Wars also loses the device during that.
7439 This->style = 0;
7440 This->exStyle = 0;
7441 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7442 pPresentationParameters->BackBufferWidth,
7443 pPresentationParameters->BackBufferHeight);
7444 This->style = style;
7445 This->exStyle = exStyle;
7448 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7449 if(FAILED(hr)) {
7450 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7453 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7454 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7456 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7457 * first use
7459 return hr;
7462 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7463 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7464 /** FIXME: always true at the moment **/
7465 if(!bEnableDialogs) {
7466 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7468 return WINED3D_OK;
7472 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7473 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7474 TRACE("(%p) : pParameters %p\n", This, pParameters);
7476 *pParameters = This->createParms;
7477 return WINED3D_OK;
7480 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7481 IWineD3DSwapChain *swapchain;
7483 TRACE("Relaying to swapchain\n");
7485 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7486 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7487 IWineD3DSwapChain_Release(swapchain);
7489 return;
7492 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7493 IWineD3DSwapChain *swapchain;
7495 TRACE("Relaying to swapchain\n");
7497 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7498 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7499 IWineD3DSwapChain_Release(swapchain);
7501 return;
7505 /** ********************************************************
7506 * Notification functions
7507 ** ********************************************************/
7508 /** This function must be called in the release of a resource when ref == 0,
7509 * the contents of resource must still be correct,
7510 * any handles to other resource held by the caller must be closed
7511 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7512 *****************************************************/
7513 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7514 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7516 TRACE("(%p) : Adding Resource %p\n", This, resource);
7517 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7520 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7521 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7523 TRACE("(%p) : Removing resource %p\n", This, resource);
7525 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7529 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7531 int counter;
7533 TRACE("(%p) : resource %p\n", This, resource);
7534 switch(IWineD3DResource_GetType(resource)){
7535 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7536 case WINED3DRTYPE_SURFACE: {
7537 unsigned int i;
7539 /* Cleanup any FBO attachments if d3d is enabled */
7540 if(This->d3d_initialized) {
7541 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7542 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7544 TRACE("Last active render target destroyed\n");
7545 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7546 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7547 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7548 * and the lastActiveRenderTarget member shouldn't matter
7550 if(swapchain) {
7551 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7552 TRACE("Activating primary back buffer\n");
7553 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7554 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7555 /* Single buffering environment */
7556 TRACE("Activating primary front buffer\n");
7557 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7558 } else {
7559 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7560 /* Implicit render target destroyed, that means the device is being destroyed
7561 * whatever we set here, it shouldn't matter
7563 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7565 } else {
7566 /* May happen during ddraw uninitialization */
7567 TRACE("Render target set, but swapchain does not exist!\n");
7568 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7572 ENTER_GL();
7573 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7574 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7575 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7576 set_render_target_fbo(iface, i, NULL);
7577 This->fbo_color_attachments[i] = NULL;
7580 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7581 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7582 set_depth_stencil_fbo(iface, NULL);
7583 This->fbo_depth_attachment = NULL;
7585 LEAVE_GL();
7588 break;
7590 case WINED3DRTYPE_TEXTURE:
7591 case WINED3DRTYPE_CUBETEXTURE:
7592 case WINED3DRTYPE_VOLUMETEXTURE:
7593 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7594 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7595 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7596 This->stateBlock->textures[counter] = NULL;
7598 if (This->updateStateBlock != This->stateBlock ){
7599 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7600 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7601 This->updateStateBlock->textures[counter] = NULL;
7605 break;
7606 case WINED3DRTYPE_VOLUME:
7607 /* TODO: nothing really? */
7608 break;
7609 case WINED3DRTYPE_VERTEXBUFFER:
7610 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7612 int streamNumber;
7613 TRACE("Cleaning up stream pointers\n");
7615 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7616 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7617 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7619 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7620 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7621 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7622 This->updateStateBlock->streamSource[streamNumber] = 0;
7623 /* Set changed flag? */
7626 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) */
7627 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7628 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7629 This->stateBlock->streamSource[streamNumber] = 0;
7632 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7633 else { /* This shouldn't happen */
7634 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7636 #endif
7640 break;
7641 case WINED3DRTYPE_INDEXBUFFER:
7642 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7643 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7644 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7645 This->updateStateBlock->pIndexData = NULL;
7648 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7649 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7650 This->stateBlock->pIndexData = NULL;
7654 break;
7655 default:
7656 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7657 break;
7661 /* Remove the resource from the resourceStore */
7662 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7664 TRACE("Resource released\n");
7668 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7670 IWineD3DResourceImpl *resource, *cursor;
7671 HRESULT ret;
7672 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7674 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7675 TRACE("enumerating resource %p\n", resource);
7676 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7677 ret = pCallback((IWineD3DResource *) resource, pData);
7678 if(ret == S_FALSE) {
7679 TRACE("Canceling enumeration\n");
7680 break;
7683 return WINED3D_OK;
7686 /**********************************************************
7687 * IWineD3DDevice VTbl follows
7688 **********************************************************/
7690 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7692 /*** IUnknown methods ***/
7693 IWineD3DDeviceImpl_QueryInterface,
7694 IWineD3DDeviceImpl_AddRef,
7695 IWineD3DDeviceImpl_Release,
7696 /*** IWineD3DDevice methods ***/
7697 IWineD3DDeviceImpl_GetParent,
7698 /*** Creation methods**/
7699 IWineD3DDeviceImpl_CreateVertexBuffer,
7700 IWineD3DDeviceImpl_CreateIndexBuffer,
7701 IWineD3DDeviceImpl_CreateStateBlock,
7702 IWineD3DDeviceImpl_CreateSurface,
7703 IWineD3DDeviceImpl_CreateTexture,
7704 IWineD3DDeviceImpl_CreateVolumeTexture,
7705 IWineD3DDeviceImpl_CreateVolume,
7706 IWineD3DDeviceImpl_CreateCubeTexture,
7707 IWineD3DDeviceImpl_CreateQuery,
7708 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7709 IWineD3DDeviceImpl_CreateVertexDeclaration,
7710 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7711 IWineD3DDeviceImpl_CreateVertexShader,
7712 IWineD3DDeviceImpl_CreatePixelShader,
7713 IWineD3DDeviceImpl_CreatePalette,
7714 /*** Odd functions **/
7715 IWineD3DDeviceImpl_Init3D,
7716 IWineD3DDeviceImpl_InitGDI,
7717 IWineD3DDeviceImpl_Uninit3D,
7718 IWineD3DDeviceImpl_UninitGDI,
7719 IWineD3DDeviceImpl_SetMultithreaded,
7720 IWineD3DDeviceImpl_EvictManagedResources,
7721 IWineD3DDeviceImpl_GetAvailableTextureMem,
7722 IWineD3DDeviceImpl_GetBackBuffer,
7723 IWineD3DDeviceImpl_GetCreationParameters,
7724 IWineD3DDeviceImpl_GetDeviceCaps,
7725 IWineD3DDeviceImpl_GetDirect3D,
7726 IWineD3DDeviceImpl_GetDisplayMode,
7727 IWineD3DDeviceImpl_SetDisplayMode,
7728 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7729 IWineD3DDeviceImpl_GetRasterStatus,
7730 IWineD3DDeviceImpl_GetSwapChain,
7731 IWineD3DDeviceImpl_Reset,
7732 IWineD3DDeviceImpl_SetDialogBoxMode,
7733 IWineD3DDeviceImpl_SetCursorProperties,
7734 IWineD3DDeviceImpl_SetCursorPosition,
7735 IWineD3DDeviceImpl_ShowCursor,
7736 IWineD3DDeviceImpl_TestCooperativeLevel,
7737 /*** Getters and setters **/
7738 IWineD3DDeviceImpl_SetClipPlane,
7739 IWineD3DDeviceImpl_GetClipPlane,
7740 IWineD3DDeviceImpl_SetClipStatus,
7741 IWineD3DDeviceImpl_GetClipStatus,
7742 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7743 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7744 IWineD3DDeviceImpl_SetDepthStencilSurface,
7745 IWineD3DDeviceImpl_GetDepthStencilSurface,
7746 IWineD3DDeviceImpl_SetFVF,
7747 IWineD3DDeviceImpl_GetFVF,
7748 IWineD3DDeviceImpl_SetGammaRamp,
7749 IWineD3DDeviceImpl_GetGammaRamp,
7750 IWineD3DDeviceImpl_SetIndices,
7751 IWineD3DDeviceImpl_GetIndices,
7752 IWineD3DDeviceImpl_SetBaseVertexIndex,
7753 IWineD3DDeviceImpl_GetBaseVertexIndex,
7754 IWineD3DDeviceImpl_SetLight,
7755 IWineD3DDeviceImpl_GetLight,
7756 IWineD3DDeviceImpl_SetLightEnable,
7757 IWineD3DDeviceImpl_GetLightEnable,
7758 IWineD3DDeviceImpl_SetMaterial,
7759 IWineD3DDeviceImpl_GetMaterial,
7760 IWineD3DDeviceImpl_SetNPatchMode,
7761 IWineD3DDeviceImpl_GetNPatchMode,
7762 IWineD3DDeviceImpl_SetPaletteEntries,
7763 IWineD3DDeviceImpl_GetPaletteEntries,
7764 IWineD3DDeviceImpl_SetPixelShader,
7765 IWineD3DDeviceImpl_GetPixelShader,
7766 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7767 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7768 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7769 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7770 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7771 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7772 IWineD3DDeviceImpl_SetRenderState,
7773 IWineD3DDeviceImpl_GetRenderState,
7774 IWineD3DDeviceImpl_SetRenderTarget,
7775 IWineD3DDeviceImpl_GetRenderTarget,
7776 IWineD3DDeviceImpl_SetFrontBackBuffers,
7777 IWineD3DDeviceImpl_SetSamplerState,
7778 IWineD3DDeviceImpl_GetSamplerState,
7779 IWineD3DDeviceImpl_SetScissorRect,
7780 IWineD3DDeviceImpl_GetScissorRect,
7781 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7782 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7783 IWineD3DDeviceImpl_SetStreamSource,
7784 IWineD3DDeviceImpl_GetStreamSource,
7785 IWineD3DDeviceImpl_SetStreamSourceFreq,
7786 IWineD3DDeviceImpl_GetStreamSourceFreq,
7787 IWineD3DDeviceImpl_SetTexture,
7788 IWineD3DDeviceImpl_GetTexture,
7789 IWineD3DDeviceImpl_SetTextureStageState,
7790 IWineD3DDeviceImpl_GetTextureStageState,
7791 IWineD3DDeviceImpl_SetTransform,
7792 IWineD3DDeviceImpl_GetTransform,
7793 IWineD3DDeviceImpl_SetVertexDeclaration,
7794 IWineD3DDeviceImpl_GetVertexDeclaration,
7795 IWineD3DDeviceImpl_SetVertexShader,
7796 IWineD3DDeviceImpl_GetVertexShader,
7797 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7798 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7799 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7800 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7801 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7802 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7803 IWineD3DDeviceImpl_SetViewport,
7804 IWineD3DDeviceImpl_GetViewport,
7805 IWineD3DDeviceImpl_MultiplyTransform,
7806 IWineD3DDeviceImpl_ValidateDevice,
7807 IWineD3DDeviceImpl_ProcessVertices,
7808 /*** State block ***/
7809 IWineD3DDeviceImpl_BeginStateBlock,
7810 IWineD3DDeviceImpl_EndStateBlock,
7811 /*** Scene management ***/
7812 IWineD3DDeviceImpl_BeginScene,
7813 IWineD3DDeviceImpl_EndScene,
7814 IWineD3DDeviceImpl_Present,
7815 IWineD3DDeviceImpl_Clear,
7816 /*** Drawing ***/
7817 IWineD3DDeviceImpl_DrawPrimitive,
7818 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7819 IWineD3DDeviceImpl_DrawPrimitiveUP,
7820 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7821 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7822 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7823 IWineD3DDeviceImpl_DrawRectPatch,
7824 IWineD3DDeviceImpl_DrawTriPatch,
7825 IWineD3DDeviceImpl_DeletePatch,
7826 IWineD3DDeviceImpl_ColorFill,
7827 IWineD3DDeviceImpl_UpdateTexture,
7828 IWineD3DDeviceImpl_UpdateSurface,
7829 IWineD3DDeviceImpl_GetFrontBufferData,
7830 /*** object tracking ***/
7831 IWineD3DDeviceImpl_ResourceReleased,
7832 IWineD3DDeviceImpl_EnumResources
7835 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7837 /*** IUnknown methods ***/
7838 IWineD3DDeviceImpl_QueryInterface,
7839 IWineD3DDeviceImpl_AddRef,
7840 IWineD3DDeviceImpl_Release,
7841 /*** IWineD3DDevice methods ***/
7842 IWineD3DDeviceImpl_GetParent,
7843 /*** Creation methods**/
7844 IWineD3DDeviceImpl_CreateVertexBuffer,
7845 IWineD3DDeviceImpl_CreateIndexBuffer,
7846 IWineD3DDeviceImpl_CreateStateBlock,
7847 IWineD3DDeviceImpl_CreateSurface,
7848 IWineD3DDeviceImpl_CreateTexture,
7849 IWineD3DDeviceImpl_CreateVolumeTexture,
7850 IWineD3DDeviceImpl_CreateVolume,
7851 IWineD3DDeviceImpl_CreateCubeTexture,
7852 IWineD3DDeviceImpl_CreateQuery,
7853 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7854 IWineD3DDeviceImpl_CreateVertexDeclaration,
7855 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7856 IWineD3DDeviceImpl_CreateVertexShader,
7857 IWineD3DDeviceImpl_CreatePixelShader,
7858 IWineD3DDeviceImpl_CreatePalette,
7859 /*** Odd functions **/
7860 IWineD3DDeviceImpl_Init3D,
7861 IWineD3DDeviceImpl_InitGDI,
7862 IWineD3DDeviceImpl_Uninit3D,
7863 IWineD3DDeviceImpl_UninitGDI,
7864 IWineD3DDeviceImpl_SetMultithreaded,
7865 IWineD3DDeviceImpl_EvictManagedResources,
7866 IWineD3DDeviceImpl_GetAvailableTextureMem,
7867 IWineD3DDeviceImpl_GetBackBuffer,
7868 IWineD3DDeviceImpl_GetCreationParameters,
7869 IWineD3DDeviceImpl_GetDeviceCaps,
7870 IWineD3DDeviceImpl_GetDirect3D,
7871 IWineD3DDeviceImpl_GetDisplayMode,
7872 IWineD3DDeviceImpl_SetDisplayMode,
7873 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7874 IWineD3DDeviceImpl_GetRasterStatus,
7875 IWineD3DDeviceImpl_GetSwapChain,
7876 IWineD3DDeviceImpl_Reset,
7877 IWineD3DDeviceImpl_SetDialogBoxMode,
7878 IWineD3DDeviceImpl_SetCursorProperties,
7879 IWineD3DDeviceImpl_SetCursorPosition,
7880 IWineD3DDeviceImpl_ShowCursor,
7881 IWineD3DDeviceImpl_TestCooperativeLevel,
7882 /*** Getters and setters **/
7883 IWineD3DDeviceImpl_SetClipPlane,
7884 IWineD3DDeviceImpl_GetClipPlane,
7885 IWineD3DDeviceImpl_SetClipStatus,
7886 IWineD3DDeviceImpl_GetClipStatus,
7887 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7888 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7889 IWineD3DDeviceImpl_SetDepthStencilSurface,
7890 IWineD3DDeviceImpl_GetDepthStencilSurface,
7891 IWineD3DDeviceImpl_SetFVF,
7892 IWineD3DDeviceImpl_GetFVF,
7893 IWineD3DDeviceImpl_SetGammaRamp,
7894 IWineD3DDeviceImpl_GetGammaRamp,
7895 IWineD3DDeviceImpl_SetIndices,
7896 IWineD3DDeviceImpl_GetIndices,
7897 IWineD3DDeviceImpl_SetBaseVertexIndex,
7898 IWineD3DDeviceImpl_GetBaseVertexIndex,
7899 IWineD3DDeviceImpl_SetLight,
7900 IWineD3DDeviceImpl_GetLight,
7901 IWineD3DDeviceImpl_SetLightEnable,
7902 IWineD3DDeviceImpl_GetLightEnable,
7903 IWineD3DDeviceImpl_SetMaterial,
7904 IWineD3DDeviceImpl_GetMaterial,
7905 IWineD3DDeviceImpl_SetNPatchMode,
7906 IWineD3DDeviceImpl_GetNPatchMode,
7907 IWineD3DDeviceImpl_SetPaletteEntries,
7908 IWineD3DDeviceImpl_GetPaletteEntries,
7909 IWineD3DDeviceImpl_SetPixelShader,
7910 IWineD3DDeviceImpl_GetPixelShader,
7911 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7912 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7913 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7914 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7915 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7916 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7917 IWineD3DDeviceImpl_SetRenderState,
7918 IWineD3DDeviceImpl_GetRenderState,
7919 IWineD3DDeviceImpl_SetRenderTarget,
7920 IWineD3DDeviceImpl_GetRenderTarget,
7921 IWineD3DDeviceImpl_SetFrontBackBuffers,
7922 IWineD3DDeviceImpl_SetSamplerState,
7923 IWineD3DDeviceImpl_GetSamplerState,
7924 IWineD3DDeviceImpl_SetScissorRect,
7925 IWineD3DDeviceImpl_GetScissorRect,
7926 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7927 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7928 IWineD3DDeviceImpl_SetStreamSource,
7929 IWineD3DDeviceImpl_GetStreamSource,
7930 IWineD3DDeviceImpl_SetStreamSourceFreq,
7931 IWineD3DDeviceImpl_GetStreamSourceFreq,
7932 IWineD3DDeviceImpl_SetTexture,
7933 IWineD3DDeviceImpl_GetTexture,
7934 IWineD3DDeviceImpl_SetTextureStageState,
7935 IWineD3DDeviceImpl_GetTextureStageState,
7936 IWineD3DDeviceImpl_SetTransform,
7937 IWineD3DDeviceImpl_GetTransform,
7938 IWineD3DDeviceImpl_SetVertexDeclaration,
7939 IWineD3DDeviceImpl_GetVertexDeclaration,
7940 IWineD3DDeviceImpl_SetVertexShader,
7941 IWineD3DDeviceImpl_GetVertexShader,
7942 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7943 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7944 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7945 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7946 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7947 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7948 IWineD3DDeviceImpl_SetViewport,
7949 IWineD3DDeviceImpl_GetViewport,
7950 IWineD3DDeviceImpl_MultiplyTransform,
7951 IWineD3DDeviceImpl_ValidateDevice,
7952 IWineD3DDeviceImpl_ProcessVertices,
7953 /*** State block ***/
7954 IWineD3DDeviceImpl_BeginStateBlock,
7955 IWineD3DDeviceImpl_EndStateBlock,
7956 /*** Scene management ***/
7957 IWineD3DDeviceImpl_BeginScene,
7958 IWineD3DDeviceImpl_EndScene,
7959 IWineD3DDeviceImpl_Present,
7960 IWineD3DDeviceImpl_Clear,
7961 /*** Drawing ***/
7962 IWineD3DDeviceImpl_DrawPrimitive,
7963 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7964 IWineD3DDeviceImpl_DrawPrimitiveUP,
7965 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7966 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7967 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7968 IWineD3DDeviceImpl_DrawRectPatch,
7969 IWineD3DDeviceImpl_DrawTriPatch,
7970 IWineD3DDeviceImpl_DeletePatch,
7971 IWineD3DDeviceImpl_ColorFill,
7972 IWineD3DDeviceImpl_UpdateTexture,
7973 IWineD3DDeviceImpl_UpdateSurface,
7974 IWineD3DDeviceImpl_GetFrontBufferData,
7975 /*** object tracking ***/
7976 IWineD3DDeviceImpl_ResourceReleased,
7977 IWineD3DDeviceImpl_EnumResources
7980 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7981 WINED3DRS_ALPHABLENDENABLE ,
7982 WINED3DRS_ALPHAFUNC ,
7983 WINED3DRS_ALPHAREF ,
7984 WINED3DRS_ALPHATESTENABLE ,
7985 WINED3DRS_BLENDOP ,
7986 WINED3DRS_COLORWRITEENABLE ,
7987 WINED3DRS_DESTBLEND ,
7988 WINED3DRS_DITHERENABLE ,
7989 WINED3DRS_FILLMODE ,
7990 WINED3DRS_FOGDENSITY ,
7991 WINED3DRS_FOGEND ,
7992 WINED3DRS_FOGSTART ,
7993 WINED3DRS_LASTPIXEL ,
7994 WINED3DRS_SHADEMODE ,
7995 WINED3DRS_SRCBLEND ,
7996 WINED3DRS_STENCILENABLE ,
7997 WINED3DRS_STENCILFAIL ,
7998 WINED3DRS_STENCILFUNC ,
7999 WINED3DRS_STENCILMASK ,
8000 WINED3DRS_STENCILPASS ,
8001 WINED3DRS_STENCILREF ,
8002 WINED3DRS_STENCILWRITEMASK ,
8003 WINED3DRS_STENCILZFAIL ,
8004 WINED3DRS_TEXTUREFACTOR ,
8005 WINED3DRS_WRAP0 ,
8006 WINED3DRS_WRAP1 ,
8007 WINED3DRS_WRAP2 ,
8008 WINED3DRS_WRAP3 ,
8009 WINED3DRS_WRAP4 ,
8010 WINED3DRS_WRAP5 ,
8011 WINED3DRS_WRAP6 ,
8012 WINED3DRS_WRAP7 ,
8013 WINED3DRS_ZENABLE ,
8014 WINED3DRS_ZFUNC ,
8015 WINED3DRS_ZWRITEENABLE
8018 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8019 WINED3DTSS_ADDRESSW ,
8020 WINED3DTSS_ALPHAARG0 ,
8021 WINED3DTSS_ALPHAARG1 ,
8022 WINED3DTSS_ALPHAARG2 ,
8023 WINED3DTSS_ALPHAOP ,
8024 WINED3DTSS_BUMPENVLOFFSET ,
8025 WINED3DTSS_BUMPENVLSCALE ,
8026 WINED3DTSS_BUMPENVMAT00 ,
8027 WINED3DTSS_BUMPENVMAT01 ,
8028 WINED3DTSS_BUMPENVMAT10 ,
8029 WINED3DTSS_BUMPENVMAT11 ,
8030 WINED3DTSS_COLORARG0 ,
8031 WINED3DTSS_COLORARG1 ,
8032 WINED3DTSS_COLORARG2 ,
8033 WINED3DTSS_COLOROP ,
8034 WINED3DTSS_RESULTARG ,
8035 WINED3DTSS_TEXCOORDINDEX ,
8036 WINED3DTSS_TEXTURETRANSFORMFLAGS
8039 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8040 WINED3DSAMP_ADDRESSU ,
8041 WINED3DSAMP_ADDRESSV ,
8042 WINED3DSAMP_ADDRESSW ,
8043 WINED3DSAMP_BORDERCOLOR ,
8044 WINED3DSAMP_MAGFILTER ,
8045 WINED3DSAMP_MINFILTER ,
8046 WINED3DSAMP_MIPFILTER ,
8047 WINED3DSAMP_MIPMAPLODBIAS ,
8048 WINED3DSAMP_MAXMIPLEVEL ,
8049 WINED3DSAMP_MAXANISOTROPY ,
8050 WINED3DSAMP_SRGBTEXTURE ,
8051 WINED3DSAMP_ELEMENTINDEX
8054 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8055 WINED3DRS_AMBIENT ,
8056 WINED3DRS_AMBIENTMATERIALSOURCE ,
8057 WINED3DRS_CLIPPING ,
8058 WINED3DRS_CLIPPLANEENABLE ,
8059 WINED3DRS_COLORVERTEX ,
8060 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8061 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8062 WINED3DRS_FOGDENSITY ,
8063 WINED3DRS_FOGEND ,
8064 WINED3DRS_FOGSTART ,
8065 WINED3DRS_FOGTABLEMODE ,
8066 WINED3DRS_FOGVERTEXMODE ,
8067 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8068 WINED3DRS_LIGHTING ,
8069 WINED3DRS_LOCALVIEWER ,
8070 WINED3DRS_MULTISAMPLEANTIALIAS ,
8071 WINED3DRS_MULTISAMPLEMASK ,
8072 WINED3DRS_NORMALIZENORMALS ,
8073 WINED3DRS_PATCHEDGESTYLE ,
8074 WINED3DRS_POINTSCALE_A ,
8075 WINED3DRS_POINTSCALE_B ,
8076 WINED3DRS_POINTSCALE_C ,
8077 WINED3DRS_POINTSCALEENABLE ,
8078 WINED3DRS_POINTSIZE ,
8079 WINED3DRS_POINTSIZE_MAX ,
8080 WINED3DRS_POINTSIZE_MIN ,
8081 WINED3DRS_POINTSPRITEENABLE ,
8082 WINED3DRS_RANGEFOGENABLE ,
8083 WINED3DRS_SPECULARMATERIALSOURCE ,
8084 WINED3DRS_TWEENFACTOR ,
8085 WINED3DRS_VERTEXBLEND ,
8086 WINED3DRS_CULLMODE ,
8087 WINED3DRS_FOGCOLOR
8090 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8091 WINED3DTSS_TEXCOORDINDEX ,
8092 WINED3DTSS_TEXTURETRANSFORMFLAGS
8095 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8096 WINED3DSAMP_DMAPOFFSET
8099 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8100 DWORD rep = This->StateTable[state].representative;
8101 DWORD idx;
8102 BYTE shift;
8103 UINT i;
8104 WineD3DContext *context;
8106 if(!rep) return;
8107 for(i = 0; i < This->numContexts; i++) {
8108 context = This->contexts[i];
8109 if(isStateDirty(context, rep)) continue;
8111 context->dirtyArray[context->numDirtyEntries++] = rep;
8112 idx = rep >> 5;
8113 shift = rep & 0x1f;
8114 context->isStateDirty[idx] |= (1 << shift);
8118 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8119 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8120 /* The drawable size of a pbuffer render target is the current pbuffer size
8122 *width = dev->pbufferWidth;
8123 *height = dev->pbufferHeight;
8126 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8127 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8129 *width = This->pow2Width;
8130 *height = This->pow2Height;
8133 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8134 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8135 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8136 * current context's drawable, which is the size of the back buffer of the swapchain
8137 * the active context belongs to. The back buffer of the swapchain is stored as the
8138 * surface the context belongs to.
8140 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8141 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;