d3d: Remove IWineD3DDevice::SetHwnd.
[wine/multimedia.git] / dlls / wined3d / device.c
blobb89db16e05048ec7e8dd5f81b6cf405df638c5b0
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) {
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 This->ddraw_width, This->ddraw_height, 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(!This->ddraw_window) {
1436 if(This->ddraw_fullscreen && object->win_handle) {
1437 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle);
1439 This->ddraw_window = object->win_handle;
1442 hDc = GetDC(object->win_handle);
1443 TRACE("Using hDc %p\n", hDc);
1445 if (NULL == hDc) {
1446 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1447 return WINED3DERR_NOTAVAILABLE;
1450 /* Get info on the current display setup */
1451 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1452 object->orig_width = Mode.Width;
1453 object->orig_height = Mode.Height;
1454 object->orig_fmt = Mode.Format;
1455 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1457 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1458 * then the corresponding dimension of the client area of the hDeviceWindow
1459 * (or the focus window, if hDeviceWindow is NULL) is taken.
1460 **********************/
1462 if (pPresentationParameters->Windowed &&
1463 ((pPresentationParameters->BackBufferWidth == 0) ||
1464 (pPresentationParameters->BackBufferHeight == 0) ||
1465 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1467 RECT Rect;
1468 GetClientRect(object->win_handle, &Rect);
1470 if (pPresentationParameters->BackBufferWidth == 0) {
1471 pPresentationParameters->BackBufferWidth = Rect.right;
1472 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1474 if (pPresentationParameters->BackBufferHeight == 0) {
1475 pPresentationParameters->BackBufferHeight = Rect.bottom;
1476 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1478 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1479 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1480 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1484 /* Put the correct figures in the presentation parameters */
1485 TRACE("Copying across presentation parameters\n");
1486 object->presentParms = *pPresentationParameters;
1488 TRACE("calling rendertarget CB\n");
1489 hr = D3DCB_CreateRenderTarget(This->parent,
1490 parent,
1491 object->presentParms.BackBufferWidth,
1492 object->presentParms.BackBufferHeight,
1493 object->presentParms.BackBufferFormat,
1494 object->presentParms.MultiSampleType,
1495 object->presentParms.MultiSampleQuality,
1496 TRUE /* Lockable */,
1497 &object->frontBuffer,
1498 NULL /* pShared (always null)*/);
1499 if (object->frontBuffer != NULL) {
1500 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1501 if(surface_type == SURFACE_OPENGL) {
1502 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1504 } else {
1505 ERR("Failed to create the front buffer\n");
1506 goto error;
1509 /*********************
1510 * Windowed / Fullscreen
1511 *******************/
1514 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1515 * so we should really check to see if there is a fullscreen swapchain already
1516 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1517 **************************************/
1519 if (!pPresentationParameters->Windowed) {
1520 WINED3DDISPLAYMODE mode;
1523 /* Change the display settings */
1524 mode.Width = pPresentationParameters->BackBufferWidth;
1525 mode.Height = pPresentationParameters->BackBufferHeight;
1526 mode.Format = pPresentationParameters->BackBufferFormat;
1527 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1529 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1530 displaymode_set = TRUE;
1531 IWineD3DDevice_SetFullscreen(iface, TRUE);
1535 * Create an opengl context for the display visual
1536 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1537 * use different properties after that point in time. FIXME: How to handle when requested format
1538 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1539 * it chooses is identical to the one already being used!
1540 **********************************/
1541 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1543 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1544 if(!object->context)
1545 return E_OUTOFMEMORY;
1546 object->num_contexts = 1;
1548 if(surface_type == SURFACE_OPENGL) {
1549 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1550 if (!object->context[0]) {
1551 ERR("Failed to create a new context\n");
1552 hr = WINED3DERR_NOTAVAILABLE;
1553 goto error;
1554 } else {
1555 TRACE("Context created (HWND=%p, glContext=%p)\n",
1556 object->win_handle, object->context[0]->glCtx);
1560 /*********************
1561 * Create the back, front and stencil buffers
1562 *******************/
1563 if(object->presentParms.BackBufferCount > 0) {
1564 int i;
1566 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1567 if(!object->backBuffer) {
1568 ERR("Out of memory\n");
1569 hr = E_OUTOFMEMORY;
1570 goto error;
1573 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1574 TRACE("calling rendertarget CB\n");
1575 hr = D3DCB_CreateRenderTarget(This->parent,
1576 parent,
1577 object->presentParms.BackBufferWidth,
1578 object->presentParms.BackBufferHeight,
1579 object->presentParms.BackBufferFormat,
1580 object->presentParms.MultiSampleType,
1581 object->presentParms.MultiSampleQuality,
1582 TRUE /* Lockable */,
1583 &object->backBuffer[i],
1584 NULL /* pShared (always null)*/);
1585 if(hr == WINED3D_OK && object->backBuffer[i]) {
1586 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1587 } else {
1588 ERR("Cannot create new back buffer\n");
1589 goto error;
1591 if(surface_type == SURFACE_OPENGL) {
1592 ENTER_GL();
1593 glDrawBuffer(GL_BACK);
1594 checkGLcall("glDrawBuffer(GL_BACK)");
1595 LEAVE_GL();
1598 } else {
1599 object->backBuffer = NULL;
1601 /* Single buffering - draw to front buffer */
1602 if(surface_type == SURFACE_OPENGL) {
1603 ENTER_GL();
1604 glDrawBuffer(GL_FRONT);
1605 checkGLcall("glDrawBuffer(GL_FRONT)");
1606 LEAVE_GL();
1610 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1611 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1612 TRACE("Creating depth stencil buffer\n");
1613 if (This->auto_depth_stencil_buffer == NULL ) {
1614 hr = D3DCB_CreateDepthStencil(This->parent,
1615 parent,
1616 object->presentParms.BackBufferWidth,
1617 object->presentParms.BackBufferHeight,
1618 object->presentParms.AutoDepthStencilFormat,
1619 object->presentParms.MultiSampleType,
1620 object->presentParms.MultiSampleQuality,
1621 FALSE /* FIXME: Discard */,
1622 &This->auto_depth_stencil_buffer,
1623 NULL /* pShared (always null)*/ );
1624 if (This->auto_depth_stencil_buffer != NULL)
1625 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1628 /** TODO: A check on width, height and multisample types
1629 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1630 ****************************/
1631 object->wantsDepthStencilBuffer = TRUE;
1632 } else {
1633 object->wantsDepthStencilBuffer = FALSE;
1636 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1638 TRACE("Created swapchain %p\n", object);
1639 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1640 return WINED3D_OK;
1642 error:
1643 if (displaymode_set) {
1644 DEVMODEW devmode;
1645 RECT clip_rc;
1647 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1648 ClipCursor(NULL);
1650 /* Change the display settings */
1651 memset(&devmode, 0, sizeof(devmode));
1652 devmode.dmSize = sizeof(devmode);
1653 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1654 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1655 devmode.dmPelsWidth = object->orig_width;
1656 devmode.dmPelsHeight = object->orig_height;
1657 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1660 if (object->backBuffer) {
1661 int i;
1662 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1663 if(object->backBuffer[i]) {
1664 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1665 IUnknown_Release(bufferParent); /* once for the get parent */
1666 if (IUnknown_Release(bufferParent) > 0) {
1667 FIXME("(%p) Something's still holding the back buffer\n",This);
1671 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1672 object->backBuffer = NULL;
1674 if(object->context[0])
1675 DestroyContext(This, object->context[0]);
1676 if(object->frontBuffer) {
1677 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1678 IUnknown_Release(bufferParent); /* once for the get parent */
1679 if (IUnknown_Release(bufferParent) > 0) {
1680 FIXME("(%p) Something's still holding the front buffer\n",This);
1683 HeapFree(GetProcessHeap(), 0, object);
1684 return hr;
1687 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1688 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1690 TRACE("(%p)\n", This);
1692 return This->NumberOfSwapChains;
1695 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1696 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1697 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1699 if(iSwapChain < This->NumberOfSwapChains) {
1700 *pSwapChain = This->swapchains[iSwapChain];
1701 IWineD3DSwapChain_AddRef(*pSwapChain);
1702 TRACE("(%p) returning %p\n", This, *pSwapChain);
1703 return WINED3D_OK;
1704 } else {
1705 TRACE("Swapchain out of range\n");
1706 *pSwapChain = NULL;
1707 return WINED3DERR_INVALIDCALL;
1711 /*****
1712 * Vertex Declaration
1713 *****/
1714 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1715 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1716 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1717 IWineD3DVertexDeclarationImpl *object = NULL;
1718 HRESULT hr = WINED3D_OK;
1720 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1721 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1723 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1725 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1726 if(FAILED(hr)) {
1727 *ppVertexDeclaration = NULL;
1728 HeapFree(GetProcessHeap(), 0, object);
1731 return hr;
1734 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1735 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1737 unsigned int idx, idx2;
1738 unsigned int offset;
1739 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1740 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1741 BOOL has_blend_idx = has_blend &&
1742 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1743 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1744 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1745 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1746 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1747 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1748 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1750 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1751 DWORD texcoords = (fvf & 0x00FF0000) >> 16;
1753 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1754 WINED3DVERTEXELEMENT *elements = NULL;
1756 unsigned int size;
1757 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1758 if (has_blend_idx) num_blends--;
1760 /* Compute declaration size */
1761 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1762 has_psize + has_diffuse + has_specular + num_textures + 1;
1764 /* convert the declaration */
1765 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1766 if (!elements)
1767 return 0;
1769 elements[size-1] = end_element;
1770 idx = 0;
1771 if (has_pos) {
1772 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1773 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1774 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1776 else {
1777 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1778 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1780 elements[idx].UsageIndex = 0;
1781 idx++;
1783 if (has_blend && (num_blends > 0)) {
1784 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1785 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1786 else
1787 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1788 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1789 elements[idx].UsageIndex = 0;
1790 idx++;
1792 if (has_blend_idx) {
1793 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1794 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1795 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1796 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1797 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1798 else
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1800 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1801 elements[idx].UsageIndex = 0;
1802 idx++;
1804 if (has_normal) {
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1806 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_psize) {
1811 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1812 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1813 elements[idx].UsageIndex = 0;
1814 idx++;
1816 if (has_diffuse) {
1817 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1818 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1819 elements[idx].UsageIndex = 0;
1820 idx++;
1822 if (has_specular) {
1823 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1824 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1825 elements[idx].UsageIndex = 1;
1826 idx++;
1828 for (idx2 = 0; idx2 < num_textures; idx2++) {
1829 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1830 switch (numcoords) {
1831 case WINED3DFVF_TEXTUREFORMAT1:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1833 break;
1834 case WINED3DFVF_TEXTUREFORMAT2:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1836 break;
1837 case WINED3DFVF_TEXTUREFORMAT3:
1838 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1839 break;
1840 case WINED3DFVF_TEXTUREFORMAT4:
1841 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1842 break;
1844 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1845 elements[idx].UsageIndex = idx2;
1846 idx++;
1849 /* Now compute offsets, and initialize the rest of the fields */
1850 for (idx = 0, offset = 0; idx < size-1; idx++) {
1851 elements[idx].Stream = 0;
1852 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1853 elements[idx].Offset = offset;
1854 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1857 *ppVertexElements = elements;
1858 return size;
1861 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1862 WINED3DVERTEXELEMENT* elements = NULL;
1863 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1864 unsigned int size;
1865 DWORD hr;
1867 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1868 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1870 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1871 HeapFree(GetProcessHeap(), 0, elements);
1872 if (hr != S_OK) return hr;
1874 return WINED3D_OK;
1877 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1878 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1879 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1880 HRESULT hr = WINED3D_OK;
1881 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1882 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1884 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1886 if (vertex_declaration) {
1887 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1890 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1892 if (WINED3D_OK != hr) {
1893 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1894 IWineD3DVertexShader_Release(*ppVertexShader);
1895 return WINED3DERR_INVALIDCALL;
1897 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1899 return WINED3D_OK;
1902 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1903 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1904 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1905 HRESULT hr = WINED3D_OK;
1907 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1908 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1909 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1910 if (WINED3D_OK == hr) {
1911 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1912 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1913 } else {
1914 WARN("(%p) : Failed to create pixel shader\n", This);
1917 return hr;
1920 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1921 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1922 IWineD3DPaletteImpl *object;
1923 HRESULT hr;
1924 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1926 /* Create the new object */
1927 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1928 if(!object) {
1929 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1930 return E_OUTOFMEMORY;
1933 object->lpVtbl = &IWineD3DPalette_Vtbl;
1934 object->ref = 1;
1935 object->Flags = Flags;
1936 object->parent = Parent;
1937 object->wineD3DDevice = This;
1938 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1940 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1942 if(!object->hpal) {
1943 HeapFree( GetProcessHeap(), 0, object);
1944 return E_OUTOFMEMORY;
1947 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1948 if(FAILED(hr)) {
1949 IWineD3DPalette_Release((IWineD3DPalette *) object);
1950 return hr;
1953 *Palette = (IWineD3DPalette *) object;
1955 return WINED3D_OK;
1958 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1959 HBITMAP hbm;
1960 BITMAP bm;
1961 HRESULT hr;
1962 HDC dcb = NULL, dcs = NULL;
1963 WINEDDCOLORKEY colorkey;
1965 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1966 if(hbm)
1968 GetObjectA(hbm, sizeof(BITMAP), &bm);
1969 dcb = CreateCompatibleDC(NULL);
1970 if(!dcb) goto out;
1971 SelectObject(dcb, hbm);
1973 else
1975 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1976 * couldn't be loaded
1978 memset(&bm, 0, sizeof(bm));
1979 bm.bmWidth = 32;
1980 bm.bmHeight = 32;
1983 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1984 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1985 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1986 if(FAILED(hr)) {
1987 ERR("Wine logo requested, but failed to create surface\n");
1988 goto out;
1991 if(dcb) {
1992 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1993 if(FAILED(hr)) goto out;
1994 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1995 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1997 colorkey.dwColorSpaceLowValue = 0;
1998 colorkey.dwColorSpaceHighValue = 0;
1999 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
2000 } else {
2001 /* Fill the surface with a white color to show that wined3d is there */
2002 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
2005 out:
2006 if(dcb) {
2007 DeleteDC(dcb);
2009 if(hbm) {
2010 DeleteObject(hbm);
2012 return;
2015 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2016 unsigned int i;
2017 /* Under DirectX you can have texture stage operations even if no texture is
2018 bound, whereas opengl will only do texture operations when a valid texture is
2019 bound. We emulate this by creating dummy textures and binding them to each
2020 texture stage, but disable all stages by default. Hence if a stage is enabled
2021 then the default texture will kick in until replaced by a SetTexture call */
2022 ENTER_GL();
2024 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2025 /* The dummy texture does not have client storage backing */
2026 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2027 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2029 for (i = 0; i < GL_LIMITS(textures); i++) {
2030 GLubyte white = 255;
2032 /* Make appropriate texture active */
2033 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2034 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2035 checkGLcall("glActiveTextureARB");
2036 } else if (i > 0) {
2037 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2040 /* Generate an opengl texture name */
2041 glGenTextures(1, &This->dummyTextureName[i]);
2042 checkGLcall("glGenTextures");
2043 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2045 /* Generate a dummy 2d texture (not using 1d because they cause many
2046 * DRI drivers fall back to sw) */
2047 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2048 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2049 checkGLcall("glBindTexture");
2051 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2052 checkGLcall("glTexImage2D");
2054 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2055 /* Reenable because if supported it is enabled by default */
2056 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2057 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2060 LEAVE_GL();
2063 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2064 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2065 IWineD3DSwapChainImpl *swapchain = NULL;
2066 HRESULT hr;
2067 DWORD state;
2068 unsigned int i;
2070 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2071 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2072 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2074 /* TODO: Test if OpenGL is compiled in and loaded */
2076 TRACE("(%p) : Creating stateblock\n", This);
2077 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2078 hr = IWineD3DDevice_CreateStateBlock(iface,
2079 WINED3DSBT_INIT,
2080 (IWineD3DStateBlock **)&This->stateBlock,
2081 NULL);
2082 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2083 WARN("Failed to create stateblock\n");
2084 goto err_out;
2086 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2087 This->updateStateBlock = This->stateBlock;
2088 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2090 hr = allocate_shader_constants(This->updateStateBlock);
2091 if (WINED3D_OK != hr) {
2092 goto err_out;
2095 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2096 This->fbo_color_attachments = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2097 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2099 This->NumberOfPalettes = 1;
2100 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2101 if(!This->palettes || !This->render_targets || !This->fbo_color_attachments || !This->draw_buffers) {
2102 ERR("Out of memory!\n");
2103 goto err_out;
2105 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2106 if(!This->palettes[0]) {
2107 ERR("Out of memory!\n");
2108 goto err_out;
2110 for (i = 0; i < 256; ++i) {
2111 This->palettes[0][i].peRed = 0xFF;
2112 This->palettes[0][i].peGreen = 0xFF;
2113 This->palettes[0][i].peBlue = 0xFF;
2114 This->palettes[0][i].peFlags = 0xFF;
2116 This->currentPalette = 0;
2118 /* Initialize the texture unit mapping to a 1:1 mapping */
2119 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2120 if (state < GL_LIMITS(fragment_samplers)) {
2121 This->texUnitMap[state] = state;
2122 This->rev_tex_unit_map[state] = state;
2123 } else {
2124 This->texUnitMap[state] = -1;
2125 This->rev_tex_unit_map[state] = -1;
2129 /* Setup the implicit swapchain */
2130 TRACE("Creating implicit swapchain\n");
2131 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2132 if (FAILED(hr) || !swapchain) {
2133 WARN("Failed to create implicit swapchain\n");
2134 goto err_out;
2137 This->NumberOfSwapChains = 1;
2138 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2139 if(!This->swapchains) {
2140 ERR("Out of memory!\n");
2141 goto err_out;
2143 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2145 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2146 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2147 This->render_targets[0] = swapchain->backBuffer[0];
2148 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2150 else {
2151 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2152 This->render_targets[0] = swapchain->frontBuffer;
2153 This->lastActiveRenderTarget = swapchain->frontBuffer;
2155 IWineD3DSurface_AddRef(This->render_targets[0]);
2156 This->activeContext = swapchain->context[0];
2157 This->lastThread = GetCurrentThreadId();
2159 /* Depth Stencil support */
2160 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2161 if (NULL != This->stencilBufferTarget) {
2162 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2165 hr = This->shader_backend->shader_alloc_private(iface);
2166 if(FAILED(hr)) {
2167 TRACE("Shader private data couldn't be allocated\n");
2168 goto err_out;
2170 hr = This->frag_pipe->alloc_private(iface);
2171 if(FAILED(hr)) {
2172 TRACE("Fragment pipeline private data couldn't be allocated\n");
2173 goto err_out;
2176 /* Set up some starting GL setup */
2178 /* Setup all the devices defaults */
2179 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2180 create_dummy_textures(This);
2182 ENTER_GL();
2184 #if 0
2185 IWineD3DImpl_CheckGraphicsMemory();
2186 #endif
2188 { /* Set a default viewport */
2189 WINED3DVIEWPORT vp;
2190 vp.X = 0;
2191 vp.Y = 0;
2192 vp.Width = pPresentationParameters->BackBufferWidth;
2193 vp.Height = pPresentationParameters->BackBufferHeight;
2194 vp.MinZ = 0.0f;
2195 vp.MaxZ = 1.0f;
2196 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2199 /* Initialize the current view state */
2200 This->view_ident = 1;
2201 This->contexts[0]->last_was_rhw = 0;
2202 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2203 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2205 switch(wined3d_settings.offscreen_rendering_mode) {
2206 case ORM_FBO:
2207 case ORM_PBUFFER:
2208 This->offscreenBuffer = GL_BACK;
2209 break;
2211 case ORM_BACKBUFFER:
2213 if(This->activeContext->aux_buffers > 0) {
2214 TRACE("Using auxilliary buffer for offscreen rendering\n");
2215 This->offscreenBuffer = GL_AUX0;
2216 } else {
2217 TRACE("Using back buffer for offscreen rendering\n");
2218 This->offscreenBuffer = GL_BACK;
2223 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2224 LEAVE_GL();
2226 /* Clear the screen */
2227 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2228 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2229 0x00, 1.0, 0);
2231 This->d3d_initialized = TRUE;
2233 if(wined3d_settings.logo) {
2234 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2236 This->highest_dirty_ps_const = 0;
2237 This->highest_dirty_vs_const = 0;
2238 return WINED3D_OK;
2240 err_out:
2241 HeapFree(GetProcessHeap(), 0, This->render_targets);
2242 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2243 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2244 HeapFree(GetProcessHeap(), 0, This->swapchains);
2245 This->NumberOfSwapChains = 0;
2246 if(This->palettes) {
2247 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2248 HeapFree(GetProcessHeap(), 0, This->palettes);
2250 This->NumberOfPalettes = 0;
2251 if(swapchain) {
2252 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2254 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2255 if(This->stateBlock) {
2256 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2257 This->stateBlock = NULL;
2259 This->frag_pipe->free_private(iface);
2260 This->shader_backend->shader_free_private(iface);
2261 return hr;
2264 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2265 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2266 IWineD3DSwapChainImpl *swapchain = NULL;
2267 HRESULT hr;
2269 /* Setup the implicit swapchain */
2270 TRACE("Creating implicit swapchain\n");
2271 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2272 if (FAILED(hr) || !swapchain) {
2273 WARN("Failed to create implicit swapchain\n");
2274 goto err_out;
2277 This->NumberOfSwapChains = 1;
2278 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2279 if(!This->swapchains) {
2280 ERR("Out of memory!\n");
2281 goto err_out;
2283 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2284 return WINED3D_OK;
2286 err_out:
2287 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2288 return hr;
2291 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2292 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2293 int sampler;
2294 UINT i;
2295 TRACE("(%p)\n", This);
2297 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2299 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2300 * it was created. Thus make sure a context is active for the glDelete* calls
2302 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2304 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2306 TRACE("Deleting high order patches\n");
2307 for(i = 0; i < PATCHMAP_SIZE; i++) {
2308 struct list *e1, *e2;
2309 struct WineD3DRectPatch *patch;
2310 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2311 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2312 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2316 /* Delete the palette conversion shader if it is around */
2317 if(This->paletteConversionShader) {
2318 ENTER_GL();
2319 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2320 LEAVE_GL();
2321 This->paletteConversionShader = 0;
2324 /* Delete the pbuffer context if there is any */
2325 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2327 /* Delete the mouse cursor texture */
2328 if(This->cursorTexture) {
2329 ENTER_GL();
2330 glDeleteTextures(1, &This->cursorTexture);
2331 LEAVE_GL();
2332 This->cursorTexture = 0;
2335 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2336 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2338 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2339 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2342 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2343 * private data, it might contain opengl pointers
2345 if(This->depth_blt_texture) {
2346 glDeleteTextures(1, &This->depth_blt_texture);
2347 This->depth_blt_texture = 0;
2349 if (This->depth_blt_rb) {
2350 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2351 This->depth_blt_rb = 0;
2352 This->depth_blt_rb_w = 0;
2353 This->depth_blt_rb_h = 0;
2356 /* Release the update stateblock */
2357 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2358 if(This->updateStateBlock != This->stateBlock)
2359 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2361 This->updateStateBlock = NULL;
2363 { /* because were not doing proper internal refcounts releasing the primary state block
2364 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2365 to set this->stateBlock = NULL; first */
2366 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2367 This->stateBlock = NULL;
2369 /* Release the stateblock */
2370 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2371 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2375 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2376 This->frag_pipe->free_private(iface);
2377 This->shader_backend->shader_free_private(iface);
2379 /* Release the buffers (with sanity checks)*/
2380 TRACE("Releasing the depth stencil buffer at %p\n", This->stencilBufferTarget);
2381 if(This->stencilBufferTarget != NULL && (IWineD3DSurface_Release(This->stencilBufferTarget) >0)){
2382 if(This->auto_depth_stencil_buffer != This->stencilBufferTarget)
2383 FIXME("(%p) Something's still holding the stencilBufferTarget\n",This);
2385 This->stencilBufferTarget = NULL;
2387 TRACE("Releasing the render target at %p\n", This->render_targets[0]);
2388 if(IWineD3DSurface_Release(This->render_targets[0]) >0){
2389 /* This check is a bit silly, it should be in swapchain_release FIXME("(%p) Something's still holding the renderTarget\n",This); */
2391 TRACE("Setting rendertarget to NULL\n");
2392 This->render_targets[0] = NULL;
2394 if (This->auto_depth_stencil_buffer) {
2395 if(D3DCB_DestroyDepthStencilSurface(This->auto_depth_stencil_buffer) > 0) {
2396 FIXME("(%p) Something's still holding the auto depth stencil buffer\n", This);
2398 This->auto_depth_stencil_buffer = NULL;
2401 for(i=0; i < This->NumberOfSwapChains; i++) {
2402 TRACE("Releasing the implicit swapchain %d\n", i);
2403 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2404 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2408 HeapFree(GetProcessHeap(), 0, This->swapchains);
2409 This->swapchains = NULL;
2410 This->NumberOfSwapChains = 0;
2412 for (i = 0; i < This->NumberOfPalettes; i++) HeapFree(GetProcessHeap(), 0, This->palettes[i]);
2413 HeapFree(GetProcessHeap(), 0, This->palettes);
2414 This->palettes = NULL;
2415 This->NumberOfPalettes = 0;
2417 HeapFree(GetProcessHeap(), 0, This->render_targets);
2418 HeapFree(GetProcessHeap(), 0, This->fbo_color_attachments);
2419 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2420 This->render_targets = NULL;
2421 This->fbo_color_attachments = NULL;
2422 This->draw_buffers = NULL;
2424 This->d3d_initialized = FALSE;
2425 return WINED3D_OK;
2428 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2430 unsigned int i;
2432 for(i=0; i < This->NumberOfSwapChains; i++) {
2433 TRACE("Releasing the implicit swapchain %d\n", i);
2434 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2435 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2439 HeapFree(GetProcessHeap(), 0, This->swapchains);
2440 This->swapchains = NULL;
2441 This->NumberOfSwapChains = 0;
2442 return WINED3D_OK;
2445 static void WINAPI IWineD3DDeviceImpl_SetFullscreen(IWineD3DDevice *iface, BOOL fullscreen) {
2446 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2447 TRACE("(%p) Setting DDraw fullscreen mode to %s\n", This, fullscreen ? "true" : "false");
2449 /* Setup the window for fullscreen mode */
2450 if(fullscreen && !This->ddraw_fullscreen) {
2451 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
2452 } else if(!fullscreen && This->ddraw_fullscreen) {
2453 IWineD3DDeviceImpl_RestoreWindow(iface, This->ddraw_window);
2456 /* DirectDraw apps can change between fullscreen and windowed mode after device creation with
2457 * IDirectDraw7::SetCooperativeLevel. The GDI surface implementation needs to know this.
2458 * DDraw doesn't necessarily have a swapchain, so we have to store the fullscreen flag
2459 * separately.
2461 This->ddraw_fullscreen = fullscreen;
2464 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2465 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2466 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2468 * There is no way to deactivate thread safety once it is enabled.
2470 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2471 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2473 /*For now just store the flag(needed in case of ddraw) */
2474 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2476 return;
2479 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2480 DEVMODEW devmode;
2481 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2482 LONG ret;
2483 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2484 RECT clip_rc;
2486 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2488 /* Resize the screen even without a window:
2489 * The app could have unset it with SetCooperativeLevel, but not called
2490 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2491 * but we don't have any hwnd
2494 memset(&devmode, 0, sizeof(devmode));
2495 devmode.dmSize = sizeof(devmode);
2496 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2497 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2498 devmode.dmPelsWidth = pMode->Width;
2499 devmode.dmPelsHeight = pMode->Height;
2501 devmode.dmDisplayFrequency = pMode->RefreshRate;
2502 if (pMode->RefreshRate != 0) {
2503 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2506 /* Only change the mode if necessary */
2507 if( (This->ddraw_width == pMode->Width) &&
2508 (This->ddraw_height == pMode->Height) &&
2509 (This->ddraw_format == pMode->Format) &&
2510 (pMode->RefreshRate == 0) ) {
2511 return WINED3D_OK;
2514 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2515 if (ret != DISP_CHANGE_SUCCESSFUL) {
2516 if(devmode.dmDisplayFrequency != 0) {
2517 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2518 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2519 devmode.dmDisplayFrequency = 0;
2520 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2522 if(ret != DISP_CHANGE_SUCCESSFUL) {
2523 return WINED3DERR_NOTAVAILABLE;
2527 /* Store the new values */
2528 This->ddraw_width = pMode->Width;
2529 This->ddraw_height = pMode->Height;
2530 This->ddraw_format = pMode->Format;
2532 /* Only do this with a window of course, and only if we're fullscreened */
2533 if(This->ddraw_window && This->ddraw_fullscreen)
2534 MoveWindow(This->ddraw_window, 0, 0, pMode->Width, pMode->Height, TRUE);
2536 /* And finally clip mouse to our screen */
2537 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2538 ClipCursor(&clip_rc);
2540 return WINED3D_OK;
2543 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2545 *ppD3D= This->wineD3D;
2546 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2547 IWineD3D_AddRef(*ppD3D);
2548 return WINED3D_OK;
2551 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2552 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2554 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2555 (This->adapter->TextureRam/(1024*1024)),
2556 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2557 /* return simulated texture memory left */
2558 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2563 /*****
2564 * Get / Set FVF
2565 *****/
2566 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2567 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2569 /* Update the current state block */
2570 This->updateStateBlock->changed.fvf = TRUE;
2572 if(This->updateStateBlock->fvf == fvf) {
2573 TRACE("Application is setting the old fvf over, nothing to do\n");
2574 return WINED3D_OK;
2577 This->updateStateBlock->fvf = fvf;
2578 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2579 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2580 return WINED3D_OK;
2584 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2585 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2586 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2587 *pfvf = This->stateBlock->fvf;
2588 return WINED3D_OK;
2591 /*****
2592 * Get / Set Stream Source
2593 *****/
2594 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2595 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2596 IWineD3DVertexBuffer *oldSrc;
2598 if (StreamNumber >= MAX_STREAMS) {
2599 WARN("Stream out of range %d\n", StreamNumber);
2600 return WINED3DERR_INVALIDCALL;
2601 } else if(OffsetInBytes & 0x3) {
2602 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2603 return WINED3DERR_INVALIDCALL;
2606 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2607 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2609 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2611 if(oldSrc == pStreamData &&
2612 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2613 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2614 TRACE("Application is setting the old values over, nothing to do\n");
2615 return WINED3D_OK;
2618 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2619 if (pStreamData) {
2620 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2621 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2624 /* Handle recording of state blocks */
2625 if (This->isRecordingState) {
2626 TRACE("Recording... not performing anything\n");
2627 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2628 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2629 return WINED3D_OK;
2632 /* Need to do a getParent and pass the references up */
2633 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2634 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2635 so for now, just count internally */
2636 if (pStreamData != NULL) {
2637 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2638 InterlockedIncrement(&vbImpl->bindCount);
2639 IWineD3DVertexBuffer_AddRef(pStreamData);
2641 if (oldSrc != NULL) {
2642 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2643 IWineD3DVertexBuffer_Release(oldSrc);
2646 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2648 return WINED3D_OK;
2651 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2652 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2654 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2655 This->stateBlock->streamSource[StreamNumber],
2656 This->stateBlock->streamOffset[StreamNumber],
2657 This->stateBlock->streamStride[StreamNumber]);
2659 if (StreamNumber >= MAX_STREAMS) {
2660 WARN("Stream out of range %d\n", StreamNumber);
2661 return WINED3DERR_INVALIDCALL;
2663 *pStream = This->stateBlock->streamSource[StreamNumber];
2664 *pStride = This->stateBlock->streamStride[StreamNumber];
2665 if (pOffset) {
2666 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2669 if (*pStream != NULL) {
2670 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2672 return WINED3D_OK;
2675 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2676 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2677 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2678 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2680 /* Verify input at least in d3d9 this is invalid*/
2681 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2682 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2683 return WINED3DERR_INVALIDCALL;
2685 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2686 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2687 return WINED3DERR_INVALIDCALL;
2689 if( Divider == 0 ){
2690 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2691 return WINED3DERR_INVALIDCALL;
2694 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2695 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2697 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2698 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2700 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2701 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2705 return WINED3D_OK;
2708 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2711 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2712 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2714 TRACE("(%p) : returning %d\n", This, *Divider);
2716 return WINED3D_OK;
2719 /*****
2720 * Get / Set & Multiply Transform
2721 *****/
2722 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2723 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2725 /* Most of this routine, comments included copied from ddraw tree initially: */
2726 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2728 /* Handle recording of state blocks */
2729 if (This->isRecordingState) {
2730 TRACE("Recording... not performing anything\n");
2731 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2732 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2733 return WINED3D_OK;
2737 * If the new matrix is the same as the current one,
2738 * we cut off any further processing. this seems to be a reasonable
2739 * optimization because as was noticed, some apps (warcraft3 for example)
2740 * tend towards setting the same matrix repeatedly for some reason.
2742 * From here on we assume that the new matrix is different, wherever it matters.
2744 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2745 TRACE("The app is setting the same matrix over again\n");
2746 return WINED3D_OK;
2747 } else {
2748 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2752 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2753 where ViewMat = Camera space, WorldMat = world space.
2755 In OpenGL, camera and world space is combined into GL_MODELVIEW
2756 matrix. The Projection matrix stay projection matrix.
2759 /* Capture the times we can just ignore the change for now */
2760 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2761 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2762 /* Handled by the state manager */
2765 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2766 return WINED3D_OK;
2769 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2771 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2772 *pMatrix = This->stateBlock->transforms[State];
2773 return WINED3D_OK;
2776 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2777 WINED3DMATRIX *mat = NULL;
2778 WINED3DMATRIX temp;
2780 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2781 * below means it will be recorded in a state block change, but it
2782 * works regardless where it is recorded.
2783 * If this is found to be wrong, change to StateBlock.
2785 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2786 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2788 if (State < HIGHEST_TRANSFORMSTATE)
2790 mat = &This->updateStateBlock->transforms[State];
2791 } else {
2792 FIXME("Unhandled transform state!!\n");
2795 multiply_matrix(&temp, mat, pMatrix);
2797 /* Apply change via set transform - will reapply to eg. lights this way */
2798 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2801 /*****
2802 * Get / Set Light
2803 *****/
2804 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2805 you can reference any indexes you want as long as that number max are enabled at any
2806 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2807 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2808 but when recording, just build a chain pretty much of commands to be replayed. */
2810 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2811 float rho;
2812 PLIGHTINFOEL *object = NULL;
2813 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2814 struct list *e;
2816 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2817 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2819 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2820 * the gl driver.
2822 if(!pLight) {
2823 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2824 return WINED3DERR_INVALIDCALL;
2827 switch(pLight->Type) {
2828 case WINED3DLIGHT_POINT:
2829 case WINED3DLIGHT_SPOT:
2830 case WINED3DLIGHT_PARALLELPOINT:
2831 case WINED3DLIGHT_GLSPOT:
2832 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2833 * most wanted
2835 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2836 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2837 return WINED3DERR_INVALIDCALL;
2839 break;
2841 case WINED3DLIGHT_DIRECTIONAL:
2842 /* Ignores attenuation */
2843 break;
2845 default:
2846 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2847 return WINED3DERR_INVALIDCALL;
2850 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2851 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2852 if(object->OriginalIndex == Index) break;
2853 object = NULL;
2856 if(!object) {
2857 TRACE("Adding new light\n");
2858 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2859 if(!object) {
2860 ERR("Out of memory error when allocating a light\n");
2861 return E_OUTOFMEMORY;
2863 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2864 object->glIndex = -1;
2865 object->OriginalIndex = Index;
2866 object->changed = TRUE;
2869 /* Initialize the object */
2870 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,
2871 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2872 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2873 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2874 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2875 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2876 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2878 /* Save away the information */
2879 object->OriginalParms = *pLight;
2881 switch (pLight->Type) {
2882 case WINED3DLIGHT_POINT:
2883 /* Position */
2884 object->lightPosn[0] = pLight->Position.x;
2885 object->lightPosn[1] = pLight->Position.y;
2886 object->lightPosn[2] = pLight->Position.z;
2887 object->lightPosn[3] = 1.0f;
2888 object->cutoff = 180.0f;
2889 /* FIXME: Range */
2890 break;
2892 case WINED3DLIGHT_DIRECTIONAL:
2893 /* Direction */
2894 object->lightPosn[0] = -pLight->Direction.x;
2895 object->lightPosn[1] = -pLight->Direction.y;
2896 object->lightPosn[2] = -pLight->Direction.z;
2897 object->lightPosn[3] = 0.0;
2898 object->exponent = 0.0f;
2899 object->cutoff = 180.0f;
2900 break;
2902 case WINED3DLIGHT_SPOT:
2903 /* Position */
2904 object->lightPosn[0] = pLight->Position.x;
2905 object->lightPosn[1] = pLight->Position.y;
2906 object->lightPosn[2] = pLight->Position.z;
2907 object->lightPosn[3] = 1.0;
2909 /* Direction */
2910 object->lightDirn[0] = pLight->Direction.x;
2911 object->lightDirn[1] = pLight->Direction.y;
2912 object->lightDirn[2] = pLight->Direction.z;
2913 object->lightDirn[3] = 1.0;
2916 * opengl-ish and d3d-ish spot lights use too different models for the
2917 * light "intensity" as a function of the angle towards the main light direction,
2918 * so we only can approximate very roughly.
2919 * however spot lights are rather rarely used in games (if ever used at all).
2920 * furthermore if still used, probably nobody pays attention to such details.
2922 if (pLight->Falloff == 0) {
2923 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2924 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2925 * will always be 1.0 for both of them, and we don't have to care for the
2926 * rest of the rather complex calculation
2928 object->exponent = 0;
2929 } else {
2930 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2931 if (rho < 0.0001) rho = 0.0001f;
2932 object->exponent = -0.3/log(cos(rho/2));
2934 if (object->exponent > 128.0) {
2935 object->exponent = 128.0;
2937 object->cutoff = pLight->Phi*90/M_PI;
2939 /* FIXME: Range */
2940 break;
2942 default:
2943 FIXME("Unrecognized light type %d\n", pLight->Type);
2946 /* Update the live definitions if the light is currently assigned a glIndex */
2947 if (object->glIndex != -1 && !This->isRecordingState) {
2948 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2950 return WINED3D_OK;
2953 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2954 PLIGHTINFOEL *lightInfo = NULL;
2955 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2956 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2957 struct list *e;
2958 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2960 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2961 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2962 if(lightInfo->OriginalIndex == Index) break;
2963 lightInfo = NULL;
2966 if (lightInfo == NULL) {
2967 TRACE("Light information requested but light not defined\n");
2968 return WINED3DERR_INVALIDCALL;
2971 *pLight = lightInfo->OriginalParms;
2972 return WINED3D_OK;
2975 /*****
2976 * Get / Set Light Enable
2977 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2978 *****/
2979 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2980 PLIGHTINFOEL *lightInfo = NULL;
2981 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2982 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2983 struct list *e;
2984 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2986 /* Tests show true = 128...not clear why */
2987 Enable = Enable? 128: 0;
2989 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2990 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2991 if(lightInfo->OriginalIndex == Index) break;
2992 lightInfo = NULL;
2994 TRACE("Found light: %p\n", lightInfo);
2996 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2997 if (lightInfo == NULL) {
2999 TRACE("Light enabled requested but light not defined, so defining one!\n");
3000 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
3002 /* Search for it again! Should be fairly quick as near head of list */
3003 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
3004 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3005 if(lightInfo->OriginalIndex == Index) break;
3006 lightInfo = NULL;
3008 if (lightInfo == NULL) {
3009 FIXME("Adding default lights has failed dismally\n");
3010 return WINED3DERR_INVALIDCALL;
3014 lightInfo->enabledChanged = TRUE;
3015 if(!Enable) {
3016 if(lightInfo->glIndex != -1) {
3017 if(!This->isRecordingState) {
3018 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
3021 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
3022 lightInfo->glIndex = -1;
3023 } else {
3024 TRACE("Light already disabled, nothing to do\n");
3026 lightInfo->enabled = FALSE;
3027 } else {
3028 lightInfo->enabled = TRUE;
3029 if (lightInfo->glIndex != -1) {
3030 /* nop */
3031 TRACE("Nothing to do as light was enabled\n");
3032 } else {
3033 int i;
3034 /* Find a free gl light */
3035 for(i = 0; i < This->maxConcurrentLights; i++) {
3036 if(This->stateBlock->activeLights[i] == NULL) {
3037 This->stateBlock->activeLights[i] = lightInfo;
3038 lightInfo->glIndex = i;
3039 break;
3042 if(lightInfo->glIndex == -1) {
3043 /* Our tests show that Windows returns D3D_OK in this situation, even with
3044 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3045 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3046 * as well for those lights.
3048 * TODO: Test how this affects rendering
3050 FIXME("Too many concurrently active lights\n");
3051 return WINED3D_OK;
3054 /* i == lightInfo->glIndex */
3055 if(!This->isRecordingState) {
3056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3061 return WINED3D_OK;
3064 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3066 PLIGHTINFOEL *lightInfo = NULL;
3067 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3068 struct list *e;
3069 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3070 TRACE("(%p) : for idx(%d)\n", This, Index);
3072 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3073 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3074 if(lightInfo->OriginalIndex == Index) break;
3075 lightInfo = NULL;
3078 if (lightInfo == NULL) {
3079 TRACE("Light enabled state requested but light not defined\n");
3080 return WINED3DERR_INVALIDCALL;
3082 /* true is 128 according to SetLightEnable */
3083 *pEnable = lightInfo->enabled ? 128 : 0;
3084 return WINED3D_OK;
3087 /*****
3088 * Get / Set Clip Planes
3089 *****/
3090 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3091 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3092 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3094 /* Validate Index */
3095 if (Index >= GL_LIMITS(clipplanes)) {
3096 TRACE("Application has requested clipplane this device doesn't support\n");
3097 return WINED3DERR_INVALIDCALL;
3100 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3102 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3103 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3104 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3105 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3106 TRACE("Application is setting old values over, nothing to do\n");
3107 return WINED3D_OK;
3110 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3111 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3112 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3113 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3115 /* Handle recording of state blocks */
3116 if (This->isRecordingState) {
3117 TRACE("Recording... not performing anything\n");
3118 return WINED3D_OK;
3121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3123 return WINED3D_OK;
3126 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3127 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3128 TRACE("(%p) : for idx %d\n", This, Index);
3130 /* Validate Index */
3131 if (Index >= GL_LIMITS(clipplanes)) {
3132 TRACE("Application has requested clipplane this device doesn't support\n");
3133 return WINED3DERR_INVALIDCALL;
3136 pPlane[0] = This->stateBlock->clipplane[Index][0];
3137 pPlane[1] = This->stateBlock->clipplane[Index][1];
3138 pPlane[2] = This->stateBlock->clipplane[Index][2];
3139 pPlane[3] = This->stateBlock->clipplane[Index][3];
3140 return WINED3D_OK;
3143 /*****
3144 * Get / Set Clip Plane Status
3145 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3146 *****/
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3149 FIXME("(%p) : stub\n", This);
3150 if (NULL == pClipStatus) {
3151 return WINED3DERR_INVALIDCALL;
3153 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3154 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3155 return WINED3D_OK;
3158 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3159 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3160 FIXME("(%p) : stub\n", This);
3161 if (NULL == pClipStatus) {
3162 return WINED3DERR_INVALIDCALL;
3164 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3165 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3166 return WINED3D_OK;
3169 /*****
3170 * Get / Set Material
3171 *****/
3172 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3173 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3175 if (!pMaterial) return WINED3DERR_INVALIDCALL;
3177 This->updateStateBlock->changed.material = TRUE;
3178 This->updateStateBlock->material = *pMaterial;
3180 /* Handle recording of state blocks */
3181 if (This->isRecordingState) {
3182 TRACE("Recording... not performing anything\n");
3183 return WINED3D_OK;
3186 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3187 return WINED3D_OK;
3190 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3191 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3192 *pMaterial = This->updateStateBlock->material;
3193 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3194 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3195 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3196 pMaterial->Ambient.b, pMaterial->Ambient.a);
3197 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3198 pMaterial->Specular.b, pMaterial->Specular.a);
3199 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3200 pMaterial->Emissive.b, pMaterial->Emissive.a);
3201 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3203 return WINED3D_OK;
3206 /*****
3207 * Get / Set Indices
3208 *****/
3209 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3210 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 IWineD3DIndexBuffer *oldIdxs;
3213 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3214 oldIdxs = This->updateStateBlock->pIndexData;
3216 This->updateStateBlock->changed.indices = TRUE;
3217 This->updateStateBlock->pIndexData = pIndexData;
3219 /* Handle recording of state blocks */
3220 if (This->isRecordingState) {
3221 TRACE("Recording... not performing anything\n");
3222 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3223 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3224 return WINED3D_OK;
3227 if(oldIdxs != pIndexData) {
3228 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3229 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3230 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3232 return WINED3D_OK;
3235 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3236 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3238 *ppIndexData = This->stateBlock->pIndexData;
3240 /* up ref count on ppindexdata */
3241 if (*ppIndexData) {
3242 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3243 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3244 }else{
3245 TRACE("(%p) No index data set\n", This);
3247 TRACE("Returning %p\n", *ppIndexData);
3249 return WINED3D_OK;
3252 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3253 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3255 TRACE("(%p)->(%d)\n", This, BaseIndex);
3257 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3258 TRACE("Application is setting the old value over, nothing to do\n");
3259 return WINED3D_OK;
3262 This->updateStateBlock->baseVertexIndex = BaseIndex;
3264 if (This->isRecordingState) {
3265 TRACE("Recording... not performing anything\n");
3266 return WINED3D_OK;
3268 /* The base vertex index affects the stream sources */
3269 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3270 return WINED3D_OK;
3273 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3274 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3275 TRACE("(%p) : base_index %p\n", This, base_index);
3277 *base_index = This->stateBlock->baseVertexIndex;
3279 TRACE("Returning %u\n", *base_index);
3281 return WINED3D_OK;
3284 /*****
3285 * Get / Set Viewports
3286 *****/
3287 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3288 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3290 TRACE("(%p)\n", This);
3291 This->updateStateBlock->changed.viewport = TRUE;
3292 This->updateStateBlock->viewport = *pViewport;
3294 /* Handle recording of state blocks */
3295 if (This->isRecordingState) {
3296 TRACE("Recording... not performing anything\n");
3297 return WINED3D_OK;
3300 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3301 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3303 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3304 return WINED3D_OK;
3308 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3310 TRACE("(%p)\n", This);
3311 *pViewport = This->stateBlock->viewport;
3312 return WINED3D_OK;
3315 /*****
3316 * Get / Set Render States
3317 * TODO: Verify against dx9 definitions
3318 *****/
3319 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3321 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3322 DWORD oldValue = This->stateBlock->renderState[State];
3324 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3326 This->updateStateBlock->changed.renderState[State] = TRUE;
3327 This->updateStateBlock->renderState[State] = Value;
3329 /* Handle recording of state blocks */
3330 if (This->isRecordingState) {
3331 TRACE("Recording... not performing anything\n");
3332 return WINED3D_OK;
3335 /* Compared here and not before the assignment to allow proper stateblock recording */
3336 if(Value == oldValue) {
3337 TRACE("Application is setting the old value over, nothing to do\n");
3338 } else {
3339 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3342 return WINED3D_OK;
3345 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3346 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3347 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3348 *pValue = This->stateBlock->renderState[State];
3349 return WINED3D_OK;
3352 /*****
3353 * Get / Set Sampler States
3354 * TODO: Verify against dx9 definitions
3355 *****/
3357 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3358 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3359 DWORD oldValue;
3361 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3362 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3364 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3365 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3368 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3369 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3370 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3373 * SetSampler is designed to allow for more than the standard up to 8 textures
3374 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3375 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3377 * http://developer.nvidia.com/object/General_FAQ.html#t6
3379 * There are two new settings for GForce
3380 * the sampler one:
3381 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3382 * and the texture one:
3383 * GL_MAX_TEXTURE_COORDS_ARB.
3384 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3385 ******************/
3387 oldValue = This->stateBlock->samplerState[Sampler][Type];
3388 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3389 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3391 /* Handle recording of state blocks */
3392 if (This->isRecordingState) {
3393 TRACE("Recording... not performing anything\n");
3394 return WINED3D_OK;
3397 if(oldValue == Value) {
3398 TRACE("Application is setting the old value over, nothing to do\n");
3399 return WINED3D_OK;
3402 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3404 return WINED3D_OK;
3407 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3408 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3410 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3411 This, Sampler, debug_d3dsamplerstate(Type), Type);
3413 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3414 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3417 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3418 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3419 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3421 *Value = This->stateBlock->samplerState[Sampler][Type];
3422 TRACE("(%p) : Returning %#x\n", This, *Value);
3424 return WINED3D_OK;
3427 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3430 This->updateStateBlock->changed.scissorRect = TRUE;
3431 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3432 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3433 return WINED3D_OK;
3435 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3437 if(This->isRecordingState) {
3438 TRACE("Recording... not performing anything\n");
3439 return WINED3D_OK;
3442 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3444 return WINED3D_OK;
3447 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3450 *pRect = This->updateStateBlock->scissorRect;
3451 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3452 return WINED3D_OK;
3455 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3456 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3457 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3459 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3461 This->updateStateBlock->vertexDecl = pDecl;
3462 This->updateStateBlock->changed.vertexDecl = TRUE;
3464 if (This->isRecordingState) {
3465 TRACE("Recording... not performing anything\n");
3466 return WINED3D_OK;
3467 } else if(pDecl == oldDecl) {
3468 /* Checked after the assignment to allow proper stateblock recording */
3469 TRACE("Application is setting the old declaration over, nothing to do\n");
3470 return WINED3D_OK;
3473 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3474 return WINED3D_OK;
3477 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3478 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3480 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3482 *ppDecl = This->stateBlock->vertexDecl;
3483 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3484 return WINED3D_OK;
3487 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3489 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3491 This->updateStateBlock->vertexShader = pShader;
3492 This->updateStateBlock->changed.vertexShader = TRUE;
3494 if (This->isRecordingState) {
3495 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3496 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3497 TRACE("Recording... not performing anything\n");
3498 return WINED3D_OK;
3499 } else if(oldShader == pShader) {
3500 /* Checked here to allow proper stateblock recording */
3501 TRACE("App is setting the old shader over, nothing to do\n");
3502 return WINED3D_OK;
3505 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3506 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3507 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3509 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3511 return WINED3D_OK;
3514 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3515 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3517 if (NULL == ppShader) {
3518 return WINED3DERR_INVALIDCALL;
3520 *ppShader = This->stateBlock->vertexShader;
3521 if( NULL != *ppShader)
3522 IWineD3DVertexShader_AddRef(*ppShader);
3524 TRACE("(%p) : returning %p\n", This, *ppShader);
3525 return WINED3D_OK;
3528 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3529 IWineD3DDevice *iface,
3530 UINT start,
3531 CONST BOOL *srcData,
3532 UINT count) {
3534 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3535 int i, cnt = min(count, MAX_CONST_B - start);
3537 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3538 iface, srcData, start, count);
3540 if (srcData == NULL || cnt < 0)
3541 return WINED3DERR_INVALIDCALL;
3543 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3544 for (i = 0; i < cnt; i++)
3545 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3547 for (i = start; i < cnt + start; ++i) {
3548 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3551 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3553 return WINED3D_OK;
3556 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3557 IWineD3DDevice *iface,
3558 UINT start,
3559 BOOL *dstData,
3560 UINT count) {
3562 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3563 int cnt = min(count, MAX_CONST_B - start);
3565 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3566 iface, dstData, start, count);
3568 if (dstData == NULL || cnt < 0)
3569 return WINED3DERR_INVALIDCALL;
3571 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3572 return WINED3D_OK;
3575 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3576 IWineD3DDevice *iface,
3577 UINT start,
3578 CONST int *srcData,
3579 UINT count) {
3581 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3582 int i, cnt = min(count, MAX_CONST_I - start);
3584 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3585 iface, srcData, start, count);
3587 if (srcData == NULL || cnt < 0)
3588 return WINED3DERR_INVALIDCALL;
3590 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3591 for (i = 0; i < cnt; i++)
3592 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3593 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3595 for (i = start; i < cnt + start; ++i) {
3596 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3599 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3601 return WINED3D_OK;
3604 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3605 IWineD3DDevice *iface,
3606 UINT start,
3607 int *dstData,
3608 UINT count) {
3610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3611 int cnt = min(count, MAX_CONST_I - start);
3613 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3614 iface, dstData, start, count);
3616 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3617 return WINED3DERR_INVALIDCALL;
3619 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3620 return WINED3D_OK;
3623 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3624 IWineD3DDevice *iface,
3625 UINT start,
3626 CONST float *srcData,
3627 UINT count) {
3629 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3630 int i;
3632 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3633 iface, srcData, start, count);
3635 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3636 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3637 return WINED3DERR_INVALIDCALL;
3639 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3640 if(TRACE_ON(d3d)) {
3641 for (i = 0; i < count; i++)
3642 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3643 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3646 for (i = start; i < count + start; ++i) {
3647 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3648 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3649 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3650 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3651 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3653 ptr->idx[ptr->count++] = i;
3654 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3658 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3660 return WINED3D_OK;
3663 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3664 IWineD3DDevice *iface,
3665 UINT start,
3666 CONST float *srcData,
3667 UINT count) {
3669 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3670 int i;
3672 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3673 iface, srcData, start, count);
3675 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3676 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3677 return WINED3DERR_INVALIDCALL;
3679 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3680 if(TRACE_ON(d3d)) {
3681 for (i = 0; i < count; i++)
3682 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3683 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3686 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3687 * context. On a context switch the old context will be fully dirtified
3689 memset(This->activeContext->vshader_const_dirty + start, 1,
3690 sizeof(*This->activeContext->vshader_const_dirty) * count);
3691 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3695 return WINED3D_OK;
3698 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3699 IWineD3DDevice *iface,
3700 UINT start,
3701 float *dstData,
3702 UINT count) {
3704 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3705 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3707 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3708 iface, dstData, start, count);
3710 if (dstData == NULL || cnt < 0)
3711 return WINED3DERR_INVALIDCALL;
3713 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3714 return WINED3D_OK;
3717 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3718 DWORD i;
3719 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3724 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3725 int i = This->rev_tex_unit_map[unit];
3726 int j = This->texUnitMap[stage];
3728 This->texUnitMap[stage] = unit;
3729 if (i != -1 && i != stage) {
3730 This->texUnitMap[i] = -1;
3733 This->rev_tex_unit_map[unit] = stage;
3734 if (j != -1 && j != unit) {
3735 This->rev_tex_unit_map[j] = -1;
3739 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3740 int i;
3742 for (i = 0; i < MAX_TEXTURES; ++i) {
3743 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3744 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3745 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3746 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3747 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3748 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3749 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3750 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3752 if (color_op == WINED3DTOP_DISABLE) {
3753 /* Not used, and disable higher stages */
3754 while (i < MAX_TEXTURES) {
3755 This->fixed_function_usage_map[i] = FALSE;
3756 ++i;
3758 break;
3761 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3762 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3763 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3764 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3765 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3766 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3767 This->fixed_function_usage_map[i] = TRUE;
3768 } else {
3769 This->fixed_function_usage_map[i] = FALSE;
3772 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3773 This->fixed_function_usage_map[i+1] = TRUE;
3778 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3779 int i, tex;
3781 device_update_fixed_function_usage_map(This);
3783 if (!GL_SUPPORT(NV_REGISTER_COMBINERS) || This->stateBlock->lowest_disabled_stage <= GL_LIMITS(textures)) {
3784 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3785 if (!This->fixed_function_usage_map[i]) continue;
3787 if (This->texUnitMap[i] != i) {
3788 device_map_stage(This, i, i);
3789 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3790 markTextureStagesDirty(This, i);
3793 return;
3796 /* Now work out the mapping */
3797 tex = 0;
3798 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3799 if (!This->fixed_function_usage_map[i]) continue;
3801 if (This->texUnitMap[i] != tex) {
3802 device_map_stage(This, i, tex);
3803 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3804 markTextureStagesDirty(This, i);
3807 ++tex;
3811 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3812 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3813 int i;
3815 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3816 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3817 device_map_stage(This, i, i);
3818 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3819 if (i < MAX_TEXTURES) {
3820 markTextureStagesDirty(This, i);
3826 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3827 int current_mapping = This->rev_tex_unit_map[unit];
3829 if (current_mapping == -1) {
3830 /* Not currently used */
3831 return TRUE;
3834 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3835 /* Used by a fragment sampler */
3837 if (!pshader_sampler_tokens) {
3838 /* No pixel shader, check fixed function */
3839 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3842 /* Pixel shader, check the shader's sampler map */
3843 return !pshader_sampler_tokens[current_mapping];
3846 /* Used by a vertex sampler */
3847 return !vshader_sampler_tokens[current_mapping];
3850 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3851 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3852 DWORD *pshader_sampler_tokens = NULL;
3853 int start = GL_LIMITS(combined_samplers) - 1;
3854 int i;
3856 if (ps) {
3857 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3859 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3860 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3861 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3864 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3865 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3866 if (vshader_sampler_tokens[i]) {
3867 if (This->texUnitMap[vsampler_idx] != -1) {
3868 /* Already mapped somewhere */
3869 continue;
3872 while (start >= 0) {
3873 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3874 device_map_stage(This, vsampler_idx, start);
3875 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3877 --start;
3878 break;
3881 --start;
3887 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3888 BOOL vs = use_vs(This);
3889 BOOL ps = use_ps(This);
3891 * Rules are:
3892 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3893 * that would be really messy and require shader recompilation
3894 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3895 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3897 if (ps) {
3898 device_map_psamplers(This);
3899 } else {
3900 device_map_fixed_function_samplers(This);
3903 if (vs) {
3904 device_map_vsamplers(This, ps);
3908 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3909 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3910 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3911 This->updateStateBlock->pixelShader = pShader;
3912 This->updateStateBlock->changed.pixelShader = TRUE;
3914 /* Handle recording of state blocks */
3915 if (This->isRecordingState) {
3916 TRACE("Recording... not performing anything\n");
3919 if (This->isRecordingState) {
3920 TRACE("Recording... not performing anything\n");
3921 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3922 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3923 return WINED3D_OK;
3926 if(pShader == oldShader) {
3927 TRACE("App is setting the old pixel shader over, nothing to do\n");
3928 return WINED3D_OK;
3931 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3932 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3934 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3935 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3937 return WINED3D_OK;
3940 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3941 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3943 if (NULL == ppShader) {
3944 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3945 return WINED3DERR_INVALIDCALL;
3948 *ppShader = This->stateBlock->pixelShader;
3949 if (NULL != *ppShader) {
3950 IWineD3DPixelShader_AddRef(*ppShader);
3952 TRACE("(%p) : returning %p\n", This, *ppShader);
3953 return WINED3D_OK;
3956 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3957 IWineD3DDevice *iface,
3958 UINT start,
3959 CONST BOOL *srcData,
3960 UINT count) {
3962 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3963 int i, cnt = min(count, MAX_CONST_B - start);
3965 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3966 iface, srcData, start, count);
3968 if (srcData == NULL || cnt < 0)
3969 return WINED3DERR_INVALIDCALL;
3971 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3972 for (i = 0; i < cnt; i++)
3973 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3975 for (i = start; i < cnt + start; ++i) {
3976 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3981 return WINED3D_OK;
3984 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3985 IWineD3DDevice *iface,
3986 UINT start,
3987 BOOL *dstData,
3988 UINT count) {
3990 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3991 int cnt = min(count, MAX_CONST_B - start);
3993 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3994 iface, dstData, start, count);
3996 if (dstData == NULL || cnt < 0)
3997 return WINED3DERR_INVALIDCALL;
3999 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
4000 return WINED3D_OK;
4003 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
4004 IWineD3DDevice *iface,
4005 UINT start,
4006 CONST int *srcData,
4007 UINT count) {
4009 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4010 int i, cnt = min(count, MAX_CONST_I - start);
4012 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4013 iface, srcData, start, count);
4015 if (srcData == NULL || cnt < 0)
4016 return WINED3DERR_INVALIDCALL;
4018 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
4019 for (i = 0; i < cnt; i++)
4020 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
4021 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4023 for (i = start; i < cnt + start; ++i) {
4024 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4027 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4029 return WINED3D_OK;
4032 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4033 IWineD3DDevice *iface,
4034 UINT start,
4035 int *dstData,
4036 UINT count) {
4038 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4039 int cnt = min(count, MAX_CONST_I - start);
4041 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4042 iface, dstData, start, count);
4044 if (dstData == NULL || cnt < 0)
4045 return WINED3DERR_INVALIDCALL;
4047 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4048 return WINED3D_OK;
4051 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4052 IWineD3DDevice *iface,
4053 UINT start,
4054 CONST float *srcData,
4055 UINT count) {
4057 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4058 int i;
4060 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4061 iface, srcData, start, count);
4063 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4064 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4065 return WINED3DERR_INVALIDCALL;
4067 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4068 if(TRACE_ON(d3d)) {
4069 for (i = 0; i < count; i++)
4070 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4071 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4074 for (i = start; i < count + start; ++i) {
4075 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4076 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4077 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4078 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4079 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4081 ptr->idx[ptr->count++] = i;
4082 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4086 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4088 return WINED3D_OK;
4091 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4092 IWineD3DDevice *iface,
4093 UINT start,
4094 CONST float *srcData,
4095 UINT count) {
4097 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4098 int i;
4100 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4101 iface, srcData, start, count);
4103 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4104 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4105 return WINED3DERR_INVALIDCALL;
4107 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4108 if(TRACE_ON(d3d)) {
4109 for (i = 0; i < count; i++)
4110 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4111 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4114 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4115 * context. On a context switch the old context will be fully dirtified
4117 memset(This->activeContext->pshader_const_dirty + start, 1,
4118 sizeof(*This->activeContext->pshader_const_dirty) * count);
4119 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4121 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4123 return WINED3D_OK;
4126 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4127 IWineD3DDevice *iface,
4128 UINT start,
4129 float *dstData,
4130 UINT count) {
4132 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4133 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4135 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4136 iface, dstData, start, count);
4138 if (dstData == NULL || cnt < 0)
4139 return WINED3DERR_INVALIDCALL;
4141 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4142 return WINED3D_OK;
4145 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4146 static HRESULT
4147 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4148 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4149 unsigned int i;
4150 DWORD DestFVF = dest->fvf;
4151 WINED3DVIEWPORT vp;
4152 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4153 BOOL doClip;
4154 int numTextures;
4156 if (lpStrideData->u.s.normal.lpData) {
4157 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4160 if (lpStrideData->u.s.position.lpData == NULL) {
4161 ERR("Source has no position mask\n");
4162 return WINED3DERR_INVALIDCALL;
4165 /* We might access VBOs from this code, so hold the lock */
4166 ENTER_GL();
4168 if (dest->resource.allocatedMemory == NULL) {
4169 /* This may happen if we do direct locking into a vbo. Unlikely,
4170 * but theoretically possible(ddraw processvertices test)
4172 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4173 if(!dest->resource.allocatedMemory) {
4174 LEAVE_GL();
4175 ERR("Out of memory\n");
4176 return E_OUTOFMEMORY;
4178 if(dest->vbo) {
4179 void *src;
4180 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4181 checkGLcall("glBindBufferARB");
4182 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4183 if(src) {
4184 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4186 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4187 checkGLcall("glUnmapBufferARB");
4191 /* Get a pointer into the destination vbo(create one if none exists) and
4192 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4194 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4195 dest->Flags |= VBFLAG_CREATEVBO;
4196 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4199 if(dest->vbo) {
4200 unsigned char extrabytes = 0;
4201 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4202 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4203 * this may write 4 extra bytes beyond the area that should be written
4205 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4206 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4207 if(!dest_conv_addr) {
4208 ERR("Out of memory\n");
4209 /* Continue without storing converted vertices */
4211 dest_conv = dest_conv_addr;
4214 /* Should I clip?
4215 * a) WINED3DRS_CLIPPING is enabled
4216 * b) WINED3DVOP_CLIP is passed
4218 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4219 static BOOL warned = FALSE;
4221 * The clipping code is not quite correct. Some things need
4222 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4223 * so disable clipping for now.
4224 * (The graphics in Half-Life are broken, and my processvertices
4225 * test crashes with IDirect3DDevice3)
4226 doClip = TRUE;
4228 doClip = FALSE;
4229 if(!warned) {
4230 warned = TRUE;
4231 FIXME("Clipping is broken and disabled for now\n");
4233 } else doClip = FALSE;
4234 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4236 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4237 WINED3DTS_VIEW,
4238 &view_mat);
4239 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4240 WINED3DTS_PROJECTION,
4241 &proj_mat);
4242 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4243 WINED3DTS_WORLDMATRIX(0),
4244 &world_mat);
4246 TRACE("View mat:\n");
4247 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);
4248 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);
4249 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);
4250 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);
4252 TRACE("Proj mat:\n");
4253 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);
4254 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);
4255 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);
4256 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);
4258 TRACE("World mat:\n");
4259 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);
4260 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);
4261 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);
4262 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);
4264 /* Get the viewport */
4265 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4266 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4267 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4269 multiply_matrix(&mat,&view_mat,&world_mat);
4270 multiply_matrix(&mat,&proj_mat,&mat);
4272 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4274 for (i = 0; i < dwCount; i+= 1) {
4275 unsigned int tex_index;
4277 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4278 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4279 /* The position first */
4280 float *p =
4281 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4282 float x, y, z, rhw;
4283 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4285 /* Multiplication with world, view and projection matrix */
4286 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);
4287 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);
4288 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);
4289 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);
4291 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4293 /* WARNING: The following things are taken from d3d7 and were not yet checked
4294 * against d3d8 or d3d9!
4297 /* Clipping conditions: From msdn
4299 * A vertex is clipped if it does not match the following requirements
4300 * -rhw < x <= rhw
4301 * -rhw < y <= rhw
4302 * 0 < z <= rhw
4303 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4305 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4306 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4310 if( !doClip ||
4311 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4312 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4313 ( rhw > eps ) ) ) {
4315 /* "Normal" viewport transformation (not clipped)
4316 * 1) The values are divided by rhw
4317 * 2) The y axis is negative, so multiply it with -1
4318 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4319 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4320 * 4) Multiply x with Width/2 and add Width/2
4321 * 5) The same for the height
4322 * 6) Add the viewpoint X and Y to the 2D coordinates and
4323 * The minimum Z value to z
4324 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4326 * Well, basically it's simply a linear transformation into viewport
4327 * coordinates
4330 x /= rhw;
4331 y /= rhw;
4332 z /= rhw;
4334 y *= -1;
4336 x *= vp.Width / 2;
4337 y *= vp.Height / 2;
4338 z *= vp.MaxZ - vp.MinZ;
4340 x += vp.Width / 2 + vp.X;
4341 y += vp.Height / 2 + vp.Y;
4342 z += vp.MinZ;
4344 rhw = 1 / rhw;
4345 } else {
4346 /* That vertex got clipped
4347 * Contrary to OpenGL it is not dropped completely, it just
4348 * undergoes a different calculation.
4350 TRACE("Vertex got clipped\n");
4351 x += rhw;
4352 y += rhw;
4354 x /= 2;
4355 y /= 2;
4357 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4358 * outside of the main vertex buffer memory. That needs some more
4359 * investigation...
4363 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4366 ( (float *) dest_ptr)[0] = x;
4367 ( (float *) dest_ptr)[1] = y;
4368 ( (float *) dest_ptr)[2] = z;
4369 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4371 dest_ptr += 3 * sizeof(float);
4373 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4374 dest_ptr += sizeof(float);
4377 if(dest_conv) {
4378 float w = 1 / rhw;
4379 ( (float *) dest_conv)[0] = x * w;
4380 ( (float *) dest_conv)[1] = y * w;
4381 ( (float *) dest_conv)[2] = z * w;
4382 ( (float *) dest_conv)[3] = w;
4384 dest_conv += 3 * sizeof(float);
4386 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4387 dest_conv += sizeof(float);
4391 if (DestFVF & WINED3DFVF_PSIZE) {
4392 dest_ptr += sizeof(DWORD);
4393 if(dest_conv) dest_conv += sizeof(DWORD);
4395 if (DestFVF & WINED3DFVF_NORMAL) {
4396 float *normal =
4397 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4398 /* AFAIK this should go into the lighting information */
4399 FIXME("Didn't expect the destination to have a normal\n");
4400 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4401 if(dest_conv) {
4402 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4406 if (DestFVF & WINED3DFVF_DIFFUSE) {
4407 DWORD *color_d =
4408 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4409 if(!color_d) {
4410 static BOOL warned = FALSE;
4412 if(!warned) {
4413 ERR("No diffuse color in source, but destination has one\n");
4414 warned = TRUE;
4417 *( (DWORD *) dest_ptr) = 0xffffffff;
4418 dest_ptr += sizeof(DWORD);
4420 if(dest_conv) {
4421 *( (DWORD *) dest_conv) = 0xffffffff;
4422 dest_conv += sizeof(DWORD);
4425 else {
4426 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4427 if(dest_conv) {
4428 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4429 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4430 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4431 dest_conv += sizeof(DWORD);
4436 if (DestFVF & WINED3DFVF_SPECULAR) {
4437 /* What's the color value in the feedback buffer? */
4438 DWORD *color_s =
4439 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4440 if(!color_s) {
4441 static BOOL warned = FALSE;
4443 if(!warned) {
4444 ERR("No specular color in source, but destination has one\n");
4445 warned = TRUE;
4448 *( (DWORD *) dest_ptr) = 0xFF000000;
4449 dest_ptr += sizeof(DWORD);
4451 if(dest_conv) {
4452 *( (DWORD *) dest_conv) = 0xFF000000;
4453 dest_conv += sizeof(DWORD);
4456 else {
4457 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4458 if(dest_conv) {
4459 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4460 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4461 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4462 dest_conv += sizeof(DWORD);
4467 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4468 float *tex_coord =
4469 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4470 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4471 if(!tex_coord) {
4472 ERR("No source texture, but destination requests one\n");
4473 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4474 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4476 else {
4477 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4478 if(dest_conv) {
4479 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4485 if(dest_conv) {
4486 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4487 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4488 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4489 dwCount * get_flexible_vertex_size(DestFVF),
4490 dest_conv_addr));
4491 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4492 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4495 LEAVE_GL();
4497 return WINED3D_OK;
4499 #undef copy_and_next
4501 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4503 WineDirect3DVertexStridedData strided;
4504 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4505 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4507 if(pVertexDecl) {
4508 ERR("Output vertex declaration not implemented yet\n");
4511 /* Need any context to write to the vbo. */
4512 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4514 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4515 * control the streamIsUP flag, thus restore it afterwards.
4517 This->stateBlock->streamIsUP = FALSE;
4518 memset(&strided, 0, sizeof(strided));
4519 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4520 This->stateBlock->streamIsUP = streamWasUP;
4522 if(vbo || SrcStartIndex) {
4523 unsigned int i;
4524 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4525 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4527 * Also get the start index in, but only loop over all elements if there's something to add at all.
4529 #define FIXSRC(type) \
4530 if(strided.u.s.type.VBO) { \
4531 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4532 strided.u.s.type.VBO = 0; \
4533 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4534 ENTER_GL(); \
4535 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4536 vb->vbo = 0; \
4537 LEAVE_GL(); \
4539 if(strided.u.s.type.lpData) { \
4540 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4542 FIXSRC(position);
4543 FIXSRC(blendWeights);
4544 FIXSRC(blendMatrixIndices);
4545 FIXSRC(normal);
4546 FIXSRC(pSize);
4547 FIXSRC(diffuse);
4548 FIXSRC(specular);
4549 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4550 FIXSRC(texCoords[i]);
4552 FIXSRC(position2);
4553 FIXSRC(normal2);
4554 FIXSRC(tangent);
4555 FIXSRC(binormal);
4556 FIXSRC(tessFactor);
4557 FIXSRC(fog);
4558 FIXSRC(depth);
4559 FIXSRC(sample);
4560 #undef FIXSRC
4563 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4566 /*****
4567 * Get / Set Texture Stage States
4568 * TODO: Verify against dx9 definitions
4569 *****/
4570 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4571 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4572 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4574 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4576 if (Stage >= MAX_TEXTURES) {
4577 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4578 return WINED3D_OK;
4581 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4582 This->updateStateBlock->textureState[Stage][Type] = Value;
4584 if (This->isRecordingState) {
4585 TRACE("Recording... not performing anything\n");
4586 return WINED3D_OK;
4589 /* Checked after the assignments to allow proper stateblock recording */
4590 if(oldValue == Value) {
4591 TRACE("App is setting the old value over, nothing to do\n");
4592 return WINED3D_OK;
4595 if(Stage > This->stateBlock->lowest_disabled_stage &&
4596 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4597 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4598 * Changes in other states are important on disabled stages too
4600 return WINED3D_OK;
4603 if(Type == WINED3DTSS_COLOROP) {
4604 int i;
4606 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4607 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4608 * they have to be disabled
4610 * The current stage is dirtified below.
4612 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4613 TRACE("Additionally dirtifying stage %d\n", i);
4614 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4616 This->stateBlock->lowest_disabled_stage = Stage;
4617 TRACE("New lowest disabled: %d\n", Stage);
4618 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4619 /* Previously disabled stage enabled. Stages above it may need enabling
4620 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4621 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4623 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4626 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4627 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4628 break;
4630 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4633 This->stateBlock->lowest_disabled_stage = i;
4634 TRACE("New lowest disabled: %d\n", i);
4636 if(GL_SUPPORT(NV_REGISTER_COMBINERS) && !This->stateBlock->pixelShader) {
4637 /* TODO: Built a stage -> texture unit mapping for register combiners */
4641 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4643 return WINED3D_OK;
4646 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4647 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4648 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4649 *pValue = This->updateStateBlock->textureState[Stage][Type];
4650 return WINED3D_OK;
4653 /*****
4654 * Get / Set Texture
4655 *****/
4656 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4658 IWineD3DBaseTexture *oldTexture;
4660 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4662 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4663 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4666 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4667 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4668 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4671 oldTexture = This->updateStateBlock->textures[Stage];
4673 if(pTexture != NULL) {
4674 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4676 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4677 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4678 return WINED3DERR_INVALIDCALL;
4680 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4683 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4684 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4686 This->updateStateBlock->changed.textures[Stage] = TRUE;
4687 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4688 This->updateStateBlock->textures[Stage] = pTexture;
4690 /* Handle recording of state blocks */
4691 if (This->isRecordingState) {
4692 TRACE("Recording... not performing anything\n");
4693 return WINED3D_OK;
4696 if(oldTexture == pTexture) {
4697 TRACE("App is setting the same texture again, nothing to do\n");
4698 return WINED3D_OK;
4701 /** NOTE: MSDN says that setTexture increases the reference count,
4702 * and that the application must set the texture back to null (or have a leaky application),
4703 * This means we should pass the refcount up to the parent
4704 *******************************/
4705 if (NULL != This->updateStateBlock->textures[Stage]) {
4706 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4707 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4709 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4710 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4711 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4712 * so the COLOROP and ALPHAOP have to be dirtified.
4714 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4715 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4717 if(bindCount == 1) {
4718 new->baseTexture.sampler = Stage;
4720 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4724 if (NULL != oldTexture) {
4725 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4726 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4728 IWineD3DBaseTexture_Release(oldTexture);
4729 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4730 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4731 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4734 if(bindCount && old->baseTexture.sampler == Stage) {
4735 int i;
4736 /* Have to do a search for the other sampler(s) where the texture is bound to
4737 * Shouldn't happen as long as apps bind a texture only to one stage
4739 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4740 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4741 if(This->updateStateBlock->textures[i] == oldTexture) {
4742 old->baseTexture.sampler = i;
4743 break;
4749 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4751 return WINED3D_OK;
4754 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4755 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4757 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4759 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4760 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4763 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4764 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4765 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4768 *ppTexture=This->stateBlock->textures[Stage];
4769 if (*ppTexture)
4770 IWineD3DBaseTexture_AddRef(*ppTexture);
4772 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4774 return WINED3D_OK;
4777 /*****
4778 * Get Back Buffer
4779 *****/
4780 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4781 IWineD3DSurface **ppBackBuffer) {
4782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4783 IWineD3DSwapChain *swapChain;
4784 HRESULT hr;
4786 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4788 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4789 if (hr == WINED3D_OK) {
4790 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4791 IWineD3DSwapChain_Release(swapChain);
4792 } else {
4793 *ppBackBuffer = NULL;
4795 return hr;
4798 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4800 WARN("(%p) : stub, calling idirect3d for now\n", This);
4801 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4804 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4805 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4806 IWineD3DSwapChain *swapChain;
4807 HRESULT hr;
4809 if(iSwapChain > 0) {
4810 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4811 if (hr == WINED3D_OK) {
4812 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4813 IWineD3DSwapChain_Release(swapChain);
4814 } else {
4815 FIXME("(%p) Error getting display mode\n", This);
4817 } else {
4818 /* Don't read the real display mode,
4819 but return the stored mode instead. X11 can't change the color
4820 depth, and some apps are pretty angry if they SetDisplayMode from
4821 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4823 Also don't relay to the swapchain because with ddraw it's possible
4824 that there isn't a swapchain at all */
4825 pMode->Width = This->ddraw_width;
4826 pMode->Height = This->ddraw_height;
4827 pMode->Format = This->ddraw_format;
4828 pMode->RefreshRate = 0;
4829 hr = WINED3D_OK;
4832 return hr;
4835 /*****
4836 * Stateblock related functions
4837 *****/
4839 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4840 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4841 IWineD3DStateBlockImpl *object;
4842 HRESULT temp_result;
4843 int i;
4845 TRACE("(%p)\n", This);
4847 if (This->isRecordingState) {
4848 return WINED3DERR_INVALIDCALL;
4851 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4852 if (NULL == object ) {
4853 FIXME("(%p)Error allocating memory for stateblock\n", This);
4854 return E_OUTOFMEMORY;
4856 TRACE("(%p) created object %p\n", This, object);
4857 object->wineD3DDevice= This;
4858 /** FIXME: object->parent = parent; **/
4859 object->parent = NULL;
4860 object->blockType = WINED3DSBT_RECORDED;
4861 object->ref = 1;
4862 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4864 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4865 list_init(&object->lightMap[i]);
4868 temp_result = allocate_shader_constants(object);
4869 if (WINED3D_OK != temp_result)
4870 return temp_result;
4872 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4873 This->updateStateBlock = object;
4874 This->isRecordingState = TRUE;
4876 TRACE("(%p) recording stateblock %p\n",This , object);
4877 return WINED3D_OK;
4880 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4881 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4882 unsigned int i, j;
4883 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4885 if (!This->isRecordingState) {
4886 FIXME("(%p) not recording! returning error\n", This);
4887 *ppStateBlock = NULL;
4888 return WINED3DERR_INVALIDCALL;
4891 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4892 if(object->changed.renderState[i]) {
4893 object->contained_render_states[object->num_contained_render_states] = i;
4894 object->num_contained_render_states++;
4897 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4898 if(object->changed.transform[i]) {
4899 object->contained_transform_states[object->num_contained_transform_states] = i;
4900 object->num_contained_transform_states++;
4903 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4904 if(object->changed.vertexShaderConstantsF[i]) {
4905 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4906 object->num_contained_vs_consts_f++;
4909 for(i = 0; i < MAX_CONST_I; i++) {
4910 if(object->changed.vertexShaderConstantsI[i]) {
4911 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4912 object->num_contained_vs_consts_i++;
4915 for(i = 0; i < MAX_CONST_B; i++) {
4916 if(object->changed.vertexShaderConstantsB[i]) {
4917 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4918 object->num_contained_vs_consts_b++;
4921 for(i = 0; i < MAX_CONST_I; i++) {
4922 if(object->changed.pixelShaderConstantsI[i]) {
4923 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4924 object->num_contained_ps_consts_i++;
4927 for(i = 0; i < MAX_CONST_B; i++) {
4928 if(object->changed.pixelShaderConstantsB[i]) {
4929 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4930 object->num_contained_ps_consts_b++;
4933 for(i = 0; i < MAX_TEXTURES; i++) {
4934 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4935 if(object->changed.textureState[i][j]) {
4936 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4937 object->contained_tss_states[object->num_contained_tss_states].state = j;
4938 object->num_contained_tss_states++;
4942 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4943 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4944 if(object->changed.samplerState[i][j]) {
4945 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4946 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4947 object->num_contained_sampler_states++;
4952 *ppStateBlock = (IWineD3DStateBlock*) object;
4953 This->isRecordingState = FALSE;
4954 This->updateStateBlock = This->stateBlock;
4955 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4956 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4957 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4958 return WINED3D_OK;
4961 /*****
4962 * Scene related functions
4963 *****/
4964 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4965 /* At the moment we have no need for any functionality at the beginning
4966 of a scene */
4967 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4968 TRACE("(%p)\n", This);
4970 if(This->inScene) {
4971 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4972 return WINED3DERR_INVALIDCALL;
4974 This->inScene = TRUE;
4975 return WINED3D_OK;
4978 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4979 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4980 TRACE("(%p)\n", This);
4982 if(!This->inScene) {
4983 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4984 return WINED3DERR_INVALIDCALL;
4987 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4988 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4989 glFlush();
4990 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4991 * fails
4994 This->inScene = FALSE;
4995 return WINED3D_OK;
4998 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4999 CONST RECT* pSourceRect, CONST RECT* pDestRect,
5000 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
5001 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5002 IWineD3DSwapChain *swapChain = NULL;
5003 int i;
5004 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
5006 TRACE("(%p) Presenting the frame\n", This);
5008 for(i = 0 ; i < swapchains ; i ++) {
5010 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
5011 TRACE("presentinng chain %d, %p\n", i, swapChain);
5012 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
5013 IWineD3DSwapChain_Release(swapChain);
5016 return WINED3D_OK;
5019 /* Not called from the VTable (internal subroutine) */
5020 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
5021 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
5022 float Z, DWORD Stencil) {
5023 GLbitfield glMask = 0;
5024 unsigned int i;
5025 WINED3DRECT curRect;
5026 RECT vp_rect;
5027 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
5028 UINT drawable_width, drawable_height;
5029 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5031 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5032 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5033 * for the cleared parts, and the untouched parts.
5035 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5036 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5037 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5038 * checking all this if the dest surface is in the drawable anyway.
5040 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5041 while(1) {
5042 if(vp->X != 0 || vp->Y != 0 ||
5043 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5044 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5045 break;
5047 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5048 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5049 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5050 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5051 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5052 break;
5054 if(Count > 0 && pRects && (
5055 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5056 pRects[0].x2 < target->currentDesc.Width ||
5057 pRects[0].y2 < target->currentDesc.Height)) {
5058 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5059 break;
5061 break;
5065 target->get_drawable_size(target, &drawable_width, &drawable_height);
5067 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5068 ENTER_GL();
5070 /* Only set the values up once, as they are not changing */
5071 if (Flags & WINED3DCLEAR_STENCIL) {
5072 glClearStencil(Stencil);
5073 checkGLcall("glClearStencil");
5074 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5075 glStencilMask(0xFFFFFFFF);
5078 if (Flags & WINED3DCLEAR_ZBUFFER) {
5079 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5080 glDepthMask(GL_TRUE);
5081 glClearDepth(Z);
5082 checkGLcall("glClearDepth");
5083 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5084 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5086 if (vp->X != 0 || vp->Y != 0 ||
5087 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5088 surface_load_ds_location(This->stencilBufferTarget, location);
5090 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5091 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5092 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5093 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5094 surface_load_ds_location(This->stencilBufferTarget, location);
5096 else if (Count > 0 && pRects && (
5097 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5098 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5099 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5100 surface_load_ds_location(This->stencilBufferTarget, location);
5104 if (Flags & WINED3DCLEAR_TARGET) {
5105 TRACE("Clearing screen with glClear to color %x\n", Color);
5106 glClearColor(D3DCOLOR_R(Color),
5107 D3DCOLOR_G(Color),
5108 D3DCOLOR_B(Color),
5109 D3DCOLOR_A(Color));
5110 checkGLcall("glClearColor");
5112 /* Clear ALL colors! */
5113 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5114 glMask = glMask | GL_COLOR_BUFFER_BIT;
5117 vp_rect.left = vp->X;
5118 vp_rect.top = vp->Y;
5119 vp_rect.right = vp->X + vp->Width;
5120 vp_rect.bottom = vp->Y + vp->Height;
5121 if (!(Count > 0 && pRects)) {
5122 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5123 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5125 if(This->render_offscreen) {
5126 glScissor(vp_rect.left, vp_rect.top,
5127 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5128 } else {
5129 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5130 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5132 checkGLcall("glScissor");
5133 glClear(glMask);
5134 checkGLcall("glClear");
5135 } else {
5136 /* Now process each rect in turn */
5137 for (i = 0; i < Count; i++) {
5138 /* Note gl uses lower left, width/height */
5139 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5140 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5141 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5143 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5144 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5145 curRect.x1, (target->currentDesc.Height - curRect.y2),
5146 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5148 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5149 * The rectangle is not cleared, no error is returned, but further rectanlges are
5150 * still cleared if they are valid
5152 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5153 TRACE("Rectangle with negative dimensions, ignoring\n");
5154 continue;
5157 if(This->render_offscreen) {
5158 glScissor(curRect.x1, curRect.y1,
5159 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5160 } else {
5161 glScissor(curRect.x1, drawable_height - curRect.y2,
5162 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5164 checkGLcall("glScissor");
5166 glClear(glMask);
5167 checkGLcall("glClear");
5171 /* Restore the old values (why..?) */
5172 if (Flags & WINED3DCLEAR_STENCIL) {
5173 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5175 if (Flags & WINED3DCLEAR_TARGET) {
5176 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5177 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5178 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5179 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5180 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5182 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5183 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5185 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5186 /* TODO: Move the fbo logic into ModifyLocation() */
5187 if(This->render_offscreen && wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
5188 target->Flags |= SFLAG_INTEXTURE;
5191 if (Flags & WINED3DCLEAR_ZBUFFER) {
5192 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5193 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5194 surface_modify_ds_location(This->stencilBufferTarget, location);
5197 LEAVE_GL();
5199 return WINED3D_OK;
5202 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5203 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5204 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5205 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5207 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5208 Count, pRects, Flags, Color, Z, Stencil);
5210 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5211 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5212 /* TODO: What about depth stencil buffers without stencil bits? */
5213 return WINED3DERR_INVALIDCALL;
5216 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5219 /*****
5220 * Drawing functions
5221 *****/
5222 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5223 UINT PrimitiveCount) {
5225 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5227 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5228 debug_d3dprimitivetype(PrimitiveType),
5229 StartVertex, PrimitiveCount);
5231 if(!This->stateBlock->vertexDecl) {
5232 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5233 return WINED3DERR_INVALIDCALL;
5236 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5237 if(This->stateBlock->streamIsUP) {
5238 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5239 This->stateBlock->streamIsUP = FALSE;
5242 if(This->stateBlock->loadBaseVertexIndex != 0) {
5243 This->stateBlock->loadBaseVertexIndex = 0;
5244 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5246 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5247 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5248 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5249 return WINED3D_OK;
5252 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5253 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5254 WINED3DPRIMITIVETYPE PrimitiveType,
5255 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5257 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5258 UINT idxStride = 2;
5259 IWineD3DIndexBuffer *pIB;
5260 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5261 GLuint vbo;
5263 pIB = This->stateBlock->pIndexData;
5264 if (!pIB) {
5265 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5266 * without an index buffer set. (The first time at least...)
5267 * D3D8 simply dies, but I doubt it can do much harm to return
5268 * D3DERR_INVALIDCALL there as well. */
5269 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5270 return WINED3DERR_INVALIDCALL;
5273 if(!This->stateBlock->vertexDecl) {
5274 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5275 return WINED3DERR_INVALIDCALL;
5278 if(This->stateBlock->streamIsUP) {
5279 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5280 This->stateBlock->streamIsUP = FALSE;
5282 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5284 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5285 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5286 minIndex, NumVertices, startIndex, primCount);
5288 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5289 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5290 idxStride = 2;
5291 } else {
5292 idxStride = 4;
5295 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5296 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5297 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5300 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5301 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5303 return WINED3D_OK;
5306 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5307 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5308 UINT VertexStreamZeroStride) {
5309 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5310 IWineD3DVertexBuffer *vb;
5312 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5313 debug_d3dprimitivetype(PrimitiveType),
5314 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5316 if(!This->stateBlock->vertexDecl) {
5317 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5318 return WINED3DERR_INVALIDCALL;
5321 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5322 vb = This->stateBlock->streamSource[0];
5323 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5324 if(vb) IWineD3DVertexBuffer_Release(vb);
5325 This->stateBlock->streamOffset[0] = 0;
5326 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5327 This->stateBlock->streamIsUP = TRUE;
5328 This->stateBlock->loadBaseVertexIndex = 0;
5330 /* TODO: Only mark dirty if drawing from a different UP address */
5331 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5333 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5334 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5336 /* MSDN specifies stream zero settings must be set to NULL */
5337 This->stateBlock->streamStride[0] = 0;
5338 This->stateBlock->streamSource[0] = NULL;
5340 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5341 * the new stream sources or use UP drawing again
5343 return WINED3D_OK;
5346 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5347 UINT MinVertexIndex, UINT NumVertices,
5348 UINT PrimitiveCount, CONST void* pIndexData,
5349 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5350 UINT VertexStreamZeroStride) {
5351 int idxStride;
5352 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5353 IWineD3DVertexBuffer *vb;
5354 IWineD3DIndexBuffer *ib;
5356 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5357 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5358 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5359 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5361 if(!This->stateBlock->vertexDecl) {
5362 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5363 return WINED3DERR_INVALIDCALL;
5366 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5367 idxStride = 2;
5368 } else {
5369 idxStride = 4;
5372 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5373 vb = This->stateBlock->streamSource[0];
5374 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5375 if(vb) IWineD3DVertexBuffer_Release(vb);
5376 This->stateBlock->streamIsUP = TRUE;
5377 This->stateBlock->streamOffset[0] = 0;
5378 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5380 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5381 This->stateBlock->baseVertexIndex = 0;
5382 This->stateBlock->loadBaseVertexIndex = 0;
5383 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5384 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5385 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5387 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5389 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5390 This->stateBlock->streamSource[0] = NULL;
5391 This->stateBlock->streamStride[0] = 0;
5392 ib = This->stateBlock->pIndexData;
5393 if(ib) {
5394 IWineD3DIndexBuffer_Release(ib);
5395 This->stateBlock->pIndexData = NULL;
5397 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5398 * SetStreamSource to specify a vertex buffer
5401 return WINED3D_OK;
5404 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5405 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5407 /* Mark the state dirty until we have nicer tracking
5408 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5409 * that value.
5411 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5412 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5413 This->stateBlock->baseVertexIndex = 0;
5414 This->up_strided = DrawPrimStrideData;
5415 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5416 This->up_strided = NULL;
5417 return WINED3D_OK;
5420 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5422 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5424 /* Mark the state dirty until we have nicer tracking
5425 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5426 * that value.
5428 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5429 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5430 This->stateBlock->streamIsUP = TRUE;
5431 This->stateBlock->baseVertexIndex = 0;
5432 This->up_strided = DrawPrimStrideData;
5433 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5434 This->up_strided = NULL;
5435 return WINED3D_OK;
5438 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5439 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5440 * not callable by the app directly no parameter validation checks are needed here.
5442 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5443 WINED3DLOCKED_BOX src;
5444 WINED3DLOCKED_BOX dst;
5445 HRESULT hr;
5446 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5448 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5449 * dirtification to improve loading performance.
5451 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5452 if(FAILED(hr)) return hr;
5453 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5454 if(FAILED(hr)) {
5455 IWineD3DVolume_UnlockBox(pSourceVolume);
5456 return hr;
5459 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5461 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5462 if(FAILED(hr)) {
5463 IWineD3DVolume_UnlockBox(pSourceVolume);
5464 } else {
5465 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5467 return hr;
5470 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5471 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5473 HRESULT hr = WINED3D_OK;
5474 WINED3DRESOURCETYPE sourceType;
5475 WINED3DRESOURCETYPE destinationType;
5476 int i ,levels;
5478 /* TODO: think about moving the code into IWineD3DBaseTexture */
5480 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5482 /* verify that the source and destination textures aren't NULL */
5483 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5484 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5485 This, pSourceTexture, pDestinationTexture);
5486 hr = WINED3DERR_INVALIDCALL;
5489 if (pSourceTexture == pDestinationTexture) {
5490 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5491 This, pSourceTexture, pDestinationTexture);
5492 hr = WINED3DERR_INVALIDCALL;
5494 /* Verify that the source and destination textures are the same type */
5495 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5496 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5498 if (sourceType != destinationType) {
5499 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5500 This);
5501 hr = WINED3DERR_INVALIDCALL;
5504 /* check that both textures have the identical numbers of levels */
5505 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5506 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5507 hr = WINED3DERR_INVALIDCALL;
5510 if (WINED3D_OK == hr) {
5512 /* Make sure that the destination texture is loaded */
5513 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5515 /* Update every surface level of the texture */
5516 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5518 switch (sourceType) {
5519 case WINED3DRTYPE_TEXTURE:
5521 IWineD3DSurface *srcSurface;
5522 IWineD3DSurface *destSurface;
5524 for (i = 0 ; i < levels ; ++i) {
5525 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5526 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5527 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5528 IWineD3DSurface_Release(srcSurface);
5529 IWineD3DSurface_Release(destSurface);
5530 if (WINED3D_OK != hr) {
5531 WARN("(%p) : Call to update surface failed\n", This);
5532 return hr;
5536 break;
5537 case WINED3DRTYPE_CUBETEXTURE:
5539 IWineD3DSurface *srcSurface;
5540 IWineD3DSurface *destSurface;
5541 WINED3DCUBEMAP_FACES faceType;
5543 for (i = 0 ; i < levels ; ++i) {
5544 /* Update each cube face */
5545 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5546 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5547 if (WINED3D_OK != hr) {
5548 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5549 } else {
5550 TRACE("Got srcSurface %p\n", srcSurface);
5552 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5553 if (WINED3D_OK != hr) {
5554 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5555 } else {
5556 TRACE("Got desrSurface %p\n", destSurface);
5558 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5559 IWineD3DSurface_Release(srcSurface);
5560 IWineD3DSurface_Release(destSurface);
5561 if (WINED3D_OK != hr) {
5562 WARN("(%p) : Call to update surface failed\n", This);
5563 return hr;
5568 break;
5570 case WINED3DRTYPE_VOLUMETEXTURE:
5572 IWineD3DVolume *srcVolume = NULL;
5573 IWineD3DVolume *destVolume = NULL;
5575 for (i = 0 ; i < levels ; ++i) {
5576 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5577 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5578 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5579 IWineD3DVolume_Release(srcVolume);
5580 IWineD3DVolume_Release(destVolume);
5581 if (WINED3D_OK != hr) {
5582 WARN("(%p) : Call to update volume failed\n", This);
5583 return hr;
5587 break;
5589 default:
5590 FIXME("(%p) : Unsupported source and destination type\n", This);
5591 hr = WINED3DERR_INVALIDCALL;
5595 return hr;
5598 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5599 IWineD3DSwapChain *swapChain;
5600 HRESULT hr;
5601 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5602 if(hr == WINED3D_OK) {
5603 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5604 IWineD3DSwapChain_Release(swapChain);
5606 return hr;
5609 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5610 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5611 /* return a sensible default */
5612 *pNumPasses = 1;
5613 /* TODO: If the window is minimized then validate device should return something other than WINED3D_OK */
5614 FIXME("(%p) : stub\n", This);
5615 return WINED3D_OK;
5618 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5620 int i;
5622 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5623 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5624 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5625 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5630 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5631 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5632 int j;
5633 UINT NewSize;
5634 PALETTEENTRY **palettes;
5636 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5638 if (PaletteNumber >= MAX_PALETTES) {
5639 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5640 return WINED3DERR_INVALIDCALL;
5643 if (PaletteNumber >= This->NumberOfPalettes) {
5644 NewSize = This->NumberOfPalettes;
5645 do {
5646 NewSize *= 2;
5647 } while(PaletteNumber >= NewSize);
5648 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5649 if (!palettes) {
5650 ERR("Out of memory!\n");
5651 return E_OUTOFMEMORY;
5653 This->palettes = palettes;
5654 This->NumberOfPalettes = NewSize;
5657 if (!This->palettes[PaletteNumber]) {
5658 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5659 if (!This->palettes[PaletteNumber]) {
5660 ERR("Out of memory!\n");
5661 return E_OUTOFMEMORY;
5665 for (j = 0; j < 256; ++j) {
5666 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5667 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5668 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5669 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5671 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5672 TRACE("(%p) : returning\n", This);
5673 return WINED3D_OK;
5676 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5678 int j;
5679 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5680 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5681 /* What happens in such situation isn't documented; Native seems to silently abort
5682 on such conditions. Return Invalid Call. */
5683 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5684 return WINED3DERR_INVALIDCALL;
5686 for (j = 0; j < 256; ++j) {
5687 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5688 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5689 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5690 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5692 TRACE("(%p) : returning\n", This);
5693 return WINED3D_OK;
5696 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5697 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5698 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5699 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5700 (tested with reference rasterizer). Return Invalid Call. */
5701 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5702 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5703 return WINED3DERR_INVALIDCALL;
5705 /*TODO: stateblocks */
5706 if (This->currentPalette != PaletteNumber) {
5707 This->currentPalette = PaletteNumber;
5708 dirtify_p8_texture_samplers(This);
5710 TRACE("(%p) : returning\n", This);
5711 return WINED3D_OK;
5714 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5715 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5716 if (PaletteNumber == NULL) {
5717 WARN("(%p) : returning Invalid Call\n", This);
5718 return WINED3DERR_INVALIDCALL;
5720 /*TODO: stateblocks */
5721 *PaletteNumber = This->currentPalette;
5722 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 static BOOL showFixmes = TRUE;
5729 if (showFixmes) {
5730 FIXME("(%p) : stub\n", This);
5731 showFixmes = FALSE;
5734 This->softwareVertexProcessing = bSoftware;
5735 return WINED3D_OK;
5739 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5740 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5741 static BOOL showFixmes = TRUE;
5742 if (showFixmes) {
5743 FIXME("(%p) : stub\n", This);
5744 showFixmes = FALSE;
5746 return This->softwareVertexProcessing;
5750 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5751 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5752 IWineD3DSwapChain *swapChain;
5753 HRESULT hr;
5755 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5757 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5758 if(hr == WINED3D_OK){
5759 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5760 IWineD3DSwapChain_Release(swapChain);
5761 }else{
5762 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5764 return hr;
5768 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5769 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5770 static BOOL showfixmes = TRUE;
5771 if(nSegments != 0.0f) {
5772 if( showfixmes) {
5773 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5774 showfixmes = FALSE;
5777 return WINED3D_OK;
5780 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 static BOOL showfixmes = TRUE;
5783 if( showfixmes) {
5784 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5785 showfixmes = FALSE;
5787 return 0.0f;
5790 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5792 /** TODO: remove casts to IWineD3DSurfaceImpl
5793 * NOTE: move code to surface to accomplish this
5794 ****************************************/
5795 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5796 int srcWidth, srcHeight;
5797 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5798 WINED3DFORMAT destFormat, srcFormat;
5799 UINT destSize;
5800 int srcLeft, destLeft, destTop;
5801 WINED3DPOOL srcPool, destPool;
5802 int offset = 0;
5803 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5804 glDescriptor *glDescription = NULL;
5805 GLenum dummy;
5806 int sampler;
5807 int bpp;
5808 CONVERT_TYPES convert = NO_CONVERSION;
5810 WINED3DSURFACE_DESC winedesc;
5812 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5813 memset(&winedesc, 0, sizeof(winedesc));
5814 winedesc.Width = &srcSurfaceWidth;
5815 winedesc.Height = &srcSurfaceHeight;
5816 winedesc.Pool = &srcPool;
5817 winedesc.Format = &srcFormat;
5819 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5821 winedesc.Width = &destSurfaceWidth;
5822 winedesc.Height = &destSurfaceHeight;
5823 winedesc.Pool = &destPool;
5824 winedesc.Format = &destFormat;
5825 winedesc.Size = &destSize;
5827 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5829 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5830 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5831 return WINED3DERR_INVALIDCALL;
5834 /* This call loads the opengl surface directly, instead of copying the surface to the
5835 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5836 * copy in sysmem and use regular surface loading.
5838 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5839 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5840 if(convert != NO_CONVERSION) {
5841 return IWineD3DSurface_BltFast(pDestinationSurface,
5842 pDestPoint ? pDestPoint->x : 0,
5843 pDestPoint ? pDestPoint->y : 0,
5844 pSourceSurface, (RECT *) pSourceRect, 0);
5847 if (destFormat == WINED3DFMT_UNKNOWN) {
5848 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5849 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5851 /* Get the update surface description */
5852 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5855 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5857 ENTER_GL();
5859 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5860 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5861 checkGLcall("glActiveTextureARB");
5864 /* Make sure the surface is loaded and up to date */
5865 IWineD3DSurface_PreLoad(pDestinationSurface);
5867 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5869 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5870 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5871 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5872 srcLeft = pSourceRect ? pSourceRect->left : 0;
5873 destLeft = pDestPoint ? pDestPoint->x : 0;
5874 destTop = pDestPoint ? pDestPoint->y : 0;
5877 /* This function doesn't support compressed textures
5878 the pitch is just bytesPerPixel * width */
5879 if(srcWidth != srcSurfaceWidth || srcLeft ){
5880 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5881 offset += srcLeft * pSrcSurface->bytesPerPixel;
5882 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5884 /* TODO DXT formats */
5886 if(pSourceRect != NULL && pSourceRect->top != 0){
5887 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5889 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5890 ,This
5891 ,glDescription->level
5892 ,destLeft
5893 ,destTop
5894 ,srcWidth
5895 ,srcHeight
5896 ,glDescription->glFormat
5897 ,glDescription->glType
5898 ,IWineD3DSurface_GetData(pSourceSurface)
5901 /* Sanity check */
5902 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5904 /* need to lock the surface to get the data */
5905 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5908 /* TODO: Cube and volume support */
5909 if(rowoffset != 0){
5910 /* not a whole row so we have to do it a line at a time */
5911 int j;
5913 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5914 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5916 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5918 glTexSubImage2D(glDescription->target
5919 ,glDescription->level
5920 ,destLeft
5922 ,srcWidth
5924 ,glDescription->glFormat
5925 ,glDescription->glType
5926 ,data /* could be quicker using */
5928 data += rowoffset;
5931 } else { /* Full width, so just write out the whole texture */
5933 if (WINED3DFMT_DXT1 == destFormat ||
5934 WINED3DFMT_DXT2 == destFormat ||
5935 WINED3DFMT_DXT3 == destFormat ||
5936 WINED3DFMT_DXT4 == destFormat ||
5937 WINED3DFMT_DXT5 == destFormat) {
5938 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5939 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5940 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5941 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5942 } if (destFormat != srcFormat) {
5943 FIXME("Updating mixed format compressed texture is not curretly support\n");
5944 } else {
5945 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5946 glDescription->level,
5947 glDescription->glFormatInternal,
5948 srcWidth,
5949 srcHeight,
5951 destSize,
5952 IWineD3DSurface_GetData(pSourceSurface));
5954 } else {
5955 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5959 } else {
5960 glTexSubImage2D(glDescription->target
5961 ,glDescription->level
5962 ,destLeft
5963 ,destTop
5964 ,srcWidth
5965 ,srcHeight
5966 ,glDescription->glFormat
5967 ,glDescription->glType
5968 ,IWineD3DSurface_GetData(pSourceSurface)
5972 checkGLcall("glTexSubImage2D");
5974 LEAVE_GL();
5976 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5977 sampler = This->rev_tex_unit_map[0];
5978 if (sampler != -1) {
5979 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5982 return WINED3D_OK;
5985 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5986 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5987 struct WineD3DRectPatch *patch;
5988 unsigned int i;
5989 struct list *e;
5990 BOOL found;
5991 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
5993 if(!(Handle || pRectPatchInfo)) {
5994 /* TODO: Write a test for the return value, thus the FIXME */
5995 FIXME("Both Handle and pRectPatchInfo are NULL\n");
5996 return WINED3DERR_INVALIDCALL;
5999 if(Handle) {
6000 i = PATCHMAP_HASHFUNC(Handle);
6001 found = FALSE;
6002 LIST_FOR_EACH(e, &This->patches[i]) {
6003 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6004 if(patch->Handle == Handle) {
6005 found = TRUE;
6006 break;
6010 if(!found) {
6011 TRACE("Patch does not exist. Creating a new one\n");
6012 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6013 patch->Handle = Handle;
6014 list_add_head(&This->patches[i], &patch->entry);
6015 } else {
6016 TRACE("Found existing patch %p\n", patch);
6018 } else {
6019 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6020 * attributes we have to tesselate, read back, and draw. This needs a patch
6021 * management structure instance. Create one.
6023 * A possible improvement is to check if a vertex shader is used, and if not directly
6024 * draw the patch.
6026 FIXME("Drawing an uncached patch. This is slow\n");
6027 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6030 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6031 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6032 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6033 HRESULT hr;
6034 TRACE("Tesselation density or patch info changed, retesselating\n");
6036 if(pRectPatchInfo) {
6037 patch->RectPatchInfo = *pRectPatchInfo;
6039 patch->numSegs[0] = pNumSegs[0];
6040 patch->numSegs[1] = pNumSegs[1];
6041 patch->numSegs[2] = pNumSegs[2];
6042 patch->numSegs[3] = pNumSegs[3];
6044 hr = tesselate_rectpatch(This, patch);
6045 if(FAILED(hr)) {
6046 WARN("Patch tesselation failed\n");
6048 /* Do not release the handle to store the params of the patch */
6049 if(!Handle) {
6050 HeapFree(GetProcessHeap(), 0, patch);
6052 return hr;
6056 This->currentPatch = patch;
6057 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6058 This->currentPatch = NULL;
6060 /* Destroy uncached patches */
6061 if(!Handle) {
6062 HeapFree(GetProcessHeap(), 0, patch->mem);
6063 HeapFree(GetProcessHeap(), 0, patch);
6065 return WINED3D_OK;
6068 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6070 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6071 FIXME("(%p) : Stub\n", This);
6072 return WINED3D_OK;
6075 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6076 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6077 int i;
6078 struct WineD3DRectPatch *patch;
6079 struct list *e;
6080 TRACE("(%p) Handle(%d)\n", This, Handle);
6082 i = PATCHMAP_HASHFUNC(Handle);
6083 LIST_FOR_EACH(e, &This->patches[i]) {
6084 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6085 if(patch->Handle == Handle) {
6086 TRACE("Deleting patch %p\n", patch);
6087 list_remove(&patch->entry);
6088 HeapFree(GetProcessHeap(), 0, patch->mem);
6089 HeapFree(GetProcessHeap(), 0, patch);
6090 return WINED3D_OK;
6094 /* TODO: Write a test for the return value */
6095 FIXME("Attempt to destroy nonexistent patch\n");
6096 return WINED3DERR_INVALIDCALL;
6099 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6100 HRESULT hr;
6101 IWineD3DSwapChain *swapchain;
6103 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6104 if (SUCCEEDED(hr)) {
6105 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6106 return swapchain;
6109 return NULL;
6112 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6113 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6115 if (!*fbo) {
6116 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6117 checkGLcall("glGenFramebuffersEXT()");
6119 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6120 checkGLcall("glBindFramebuffer()");
6123 /* TODO: Handle stencil attachments */
6124 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6125 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6127 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6128 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6129 checkGLcall("glFramebufferRenderbufferEXT()");
6130 } else {
6131 IWineD3DBaseTextureImpl *texture_impl;
6132 GLenum texttarget, target;
6133 GLint old_binding = 0;
6135 texttarget = depth_stencil_impl->glDescription.target;
6136 if(texttarget == GL_TEXTURE_2D) {
6137 target = GL_TEXTURE_2D;
6138 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6139 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6140 target = GL_TEXTURE_RECTANGLE_ARB;
6141 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6142 } else {
6143 target = GL_TEXTURE_CUBE_MAP_ARB;
6144 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6147 IWineD3DSurface_PreLoad(depth_stencil);
6149 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6150 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6151 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6152 glBindTexture(target, old_binding);
6154 /* Update base texture states array */
6155 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6156 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6157 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6158 if (texture_impl->baseTexture.bindCount) {
6159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6162 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6165 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6166 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6167 checkGLcall("glFramebufferTexture2DEXT()");
6171 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6172 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6173 IWineD3DBaseTextureImpl *texture_impl;
6174 GLenum texttarget, target;
6175 GLint old_binding;
6177 texttarget = surface_impl->glDescription.target;
6178 if(texttarget == GL_TEXTURE_2D) {
6179 target = GL_TEXTURE_2D;
6180 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6181 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6182 target = GL_TEXTURE_RECTANGLE_ARB;
6183 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6184 } else {
6185 target = GL_TEXTURE_CUBE_MAP_ARB;
6186 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6189 IWineD3DSurface_PreLoad(surface);
6191 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6192 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6193 glBindTexture(target, old_binding);
6195 /* Update base texture states array */
6196 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6197 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6198 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6199 if (texture_impl->baseTexture.bindCount) {
6200 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6203 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6206 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6207 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6209 checkGLcall("attach_surface_fbo");
6212 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6213 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6214 IWineD3DSwapChain *swapchain;
6216 swapchain = get_swapchain(surface);
6217 if (swapchain) {
6218 GLenum buffer;
6220 TRACE("Surface %p is onscreen\n", surface);
6222 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6223 ENTER_GL();
6224 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6225 buffer = surface_get_gl_buffer(surface, swapchain);
6226 glDrawBuffer(buffer);
6227 checkGLcall("glDrawBuffer()");
6228 } else {
6229 TRACE("Surface %p is offscreen\n", surface);
6231 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6232 ENTER_GL();
6233 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->dst_fbo);
6234 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6235 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6236 checkGLcall("glFramebufferRenderbufferEXT");
6239 if (rect) {
6240 glEnable(GL_SCISSOR_TEST);
6241 if(!swapchain) {
6242 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6243 } else {
6244 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6245 rect->x2 - rect->x1, rect->y2 - rect->y1);
6247 checkGLcall("glScissor");
6248 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6249 } else {
6250 glDisable(GL_SCISSOR_TEST);
6252 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6254 glDisable(GL_BLEND);
6255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6257 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6258 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6260 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6261 glClear(GL_COLOR_BUFFER_BIT);
6262 checkGLcall("glClear");
6264 if (This->render_offscreen) {
6265 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6266 } else {
6267 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6268 checkGLcall("glBindFramebuffer()");
6271 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6272 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6273 glDrawBuffer(GL_BACK);
6274 checkGLcall("glDrawBuffer()");
6277 LEAVE_GL();
6280 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6281 unsigned int r, g, b, a;
6282 DWORD ret;
6284 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6285 destfmt == WINED3DFMT_R8G8B8)
6286 return color;
6288 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6290 a = (color & 0xff000000) >> 24;
6291 r = (color & 0x00ff0000) >> 16;
6292 g = (color & 0x0000ff00) >> 8;
6293 b = (color & 0x000000ff) >> 0;
6295 switch(destfmt)
6297 case WINED3DFMT_R5G6B5:
6298 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6299 r = (r * 32) / 256;
6300 g = (g * 64) / 256;
6301 b = (b * 32) / 256;
6302 ret = r << 11;
6303 ret |= g << 5;
6304 ret |= b;
6305 TRACE("Returning %08x\n", ret);
6306 return ret;
6308 case WINED3DFMT_X1R5G5B5:
6309 case WINED3DFMT_A1R5G5B5:
6310 a = (a * 2) / 256;
6311 r = (r * 32) / 256;
6312 g = (g * 32) / 256;
6313 b = (b * 32) / 256;
6314 ret = a << 15;
6315 ret |= r << 10;
6316 ret |= g << 5;
6317 ret |= b << 0;
6318 TRACE("Returning %08x\n", ret);
6319 return ret;
6321 case WINED3DFMT_A8:
6322 TRACE("Returning %08x\n", a);
6323 return a;
6325 case WINED3DFMT_X4R4G4B4:
6326 case WINED3DFMT_A4R4G4B4:
6327 a = (a * 16) / 256;
6328 r = (r * 16) / 256;
6329 g = (g * 16) / 256;
6330 b = (b * 16) / 256;
6331 ret = a << 12;
6332 ret |= r << 8;
6333 ret |= g << 4;
6334 ret |= b << 0;
6335 TRACE("Returning %08x\n", ret);
6336 return ret;
6338 case WINED3DFMT_R3G3B2:
6339 r = (r * 8) / 256;
6340 g = (g * 8) / 256;
6341 b = (b * 4) / 256;
6342 ret = r << 5;
6343 ret |= g << 2;
6344 ret |= b << 0;
6345 TRACE("Returning %08x\n", ret);
6346 return ret;
6348 case WINED3DFMT_X8B8G8R8:
6349 case WINED3DFMT_A8B8G8R8:
6350 ret = a << 24;
6351 ret |= b << 16;
6352 ret |= g << 8;
6353 ret |= r << 0;
6354 TRACE("Returning %08x\n", ret);
6355 return ret;
6357 case WINED3DFMT_A2R10G10B10:
6358 a = (a * 4) / 256;
6359 r = (r * 1024) / 256;
6360 g = (g * 1024) / 256;
6361 b = (b * 1024) / 256;
6362 ret = a << 30;
6363 ret |= r << 20;
6364 ret |= g << 10;
6365 ret |= b << 0;
6366 TRACE("Returning %08x\n", ret);
6367 return ret;
6369 case WINED3DFMT_A2B10G10R10:
6370 a = (a * 4) / 256;
6371 r = (r * 1024) / 256;
6372 g = (g * 1024) / 256;
6373 b = (b * 1024) / 256;
6374 ret = a << 30;
6375 ret |= b << 20;
6376 ret |= g << 10;
6377 ret |= r << 0;
6378 TRACE("Returning %08x\n", ret);
6379 return ret;
6381 default:
6382 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6383 return 0;
6387 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6388 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6389 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6390 WINEDDBLTFX BltFx;
6391 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6393 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6394 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6395 return WINED3DERR_INVALIDCALL;
6398 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6399 color_fill_fbo(iface, pSurface, pRect, color);
6400 return WINED3D_OK;
6401 } else {
6402 /* Just forward this to the DirectDraw blitting engine */
6403 memset(&BltFx, 0, sizeof(BltFx));
6404 BltFx.dwSize = sizeof(BltFx);
6405 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6406 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6410 /* rendertarget and depth stencil functions */
6411 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6412 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6414 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6415 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6416 return WINED3DERR_INVALIDCALL;
6419 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6420 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6421 /* Note inc ref on returned surface */
6422 if(*ppRenderTarget != NULL)
6423 IWineD3DSurface_AddRef(*ppRenderTarget);
6424 return WINED3D_OK;
6427 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6429 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6430 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6431 IWineD3DSwapChainImpl *Swapchain;
6432 HRESULT hr;
6434 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6436 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6437 if(hr != WINED3D_OK) {
6438 ERR("Can't get the swapchain\n");
6439 return hr;
6442 /* Make sure to release the swapchain */
6443 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6445 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6446 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6447 return WINED3DERR_INVALIDCALL;
6449 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6450 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6451 return WINED3DERR_INVALIDCALL;
6454 if(Swapchain->frontBuffer != Front) {
6455 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6457 if(Swapchain->frontBuffer)
6458 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6459 Swapchain->frontBuffer = Front;
6461 if(Swapchain->frontBuffer) {
6462 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6466 if(Back && !Swapchain->backBuffer) {
6467 /* We need memory for the back buffer array - only one back buffer this way */
6468 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6469 if(!Swapchain->backBuffer) {
6470 ERR("Out of memory\n");
6471 return E_OUTOFMEMORY;
6475 if(Swapchain->backBuffer[0] != Back) {
6476 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6478 /* What to do about the context here in the case of multithreading? Not sure.
6479 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6481 ENTER_GL();
6482 if(!Swapchain->backBuffer[0]) {
6483 /* GL was told to draw to the front buffer at creation,
6484 * undo that
6486 glDrawBuffer(GL_BACK);
6487 checkGLcall("glDrawBuffer(GL_BACK)");
6488 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6489 Swapchain->presentParms.BackBufferCount = 1;
6490 } else if (!Back) {
6491 /* That makes problems - disable for now */
6492 /* glDrawBuffer(GL_FRONT); */
6493 checkGLcall("glDrawBuffer(GL_FRONT)");
6494 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6495 Swapchain->presentParms.BackBufferCount = 0;
6497 LEAVE_GL();
6499 if(Swapchain->backBuffer[0])
6500 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6501 Swapchain->backBuffer[0] = Back;
6503 if(Swapchain->backBuffer[0]) {
6504 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6505 } else {
6506 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6507 Swapchain->backBuffer = NULL;
6512 return WINED3D_OK;
6515 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6516 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6517 *ppZStencilSurface = This->stencilBufferTarget;
6518 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6520 if(*ppZStencilSurface != NULL) {
6521 /* Note inc ref on returned surface */
6522 IWineD3DSurface_AddRef(*ppZStencilSurface);
6523 return WINED3D_OK;
6524 } else {
6525 return WINED3DERR_NOTFOUND;
6529 /* TODO: Handle stencil attachments */
6530 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6531 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 TRACE("Set depth stencil to %p\n", depth_stencil);
6535 if (depth_stencil) {
6536 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6537 } else {
6538 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6539 checkGLcall("glFramebufferTexture2DEXT()");
6543 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6544 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6546 TRACE("Set render target %u to %p\n", idx, render_target);
6548 if (render_target) {
6549 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6550 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6551 } else {
6552 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6553 checkGLcall("glFramebufferTexture2DEXT()");
6555 This->draw_buffers[idx] = GL_NONE;
6559 static void check_fbo_status(IWineD3DDevice *iface) {
6560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6561 GLenum status;
6563 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6564 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6565 TRACE("FBO complete\n");
6566 } else {
6567 IWineD3DSurfaceImpl *attachment;
6568 int i;
6569 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6571 /* Dump the FBO attachments */
6572 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6573 attachment = (IWineD3DSurfaceImpl *)This->fbo_color_attachments[i];
6574 if (attachment) {
6575 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6576 attachment->pow2Width, attachment->pow2Height);
6579 attachment = (IWineD3DSurfaceImpl *)This->fbo_depth_attachment;
6580 if (attachment) {
6581 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6582 attachment->pow2Width, attachment->pow2Height);
6587 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6588 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6589 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6590 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6592 if (!ds_impl) return FALSE;
6594 if (ds_impl->current_renderbuffer) {
6595 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6596 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6599 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6600 rt_impl->pow2Height != ds_impl->pow2Height);
6603 void apply_fbo_state(IWineD3DDevice *iface) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6605 unsigned int i;
6607 if (This->render_offscreen) {
6608 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6610 /* Apply render targets */
6611 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6612 IWineD3DSurface *render_target = This->render_targets[i];
6613 if (This->fbo_color_attachments[i] != render_target) {
6614 set_render_target_fbo(iface, i, render_target);
6615 This->fbo_color_attachments[i] = render_target;
6619 /* Apply depth targets */
6620 if (This->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6621 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6622 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6624 if (This->stencilBufferTarget) {
6625 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6627 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6628 This->fbo_depth_attachment = This->stencilBufferTarget;
6630 } else {
6631 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6634 check_fbo_status(iface);
6637 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6638 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6639 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6640 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6641 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6642 GLenum gl_filter;
6643 POINT offset = {0, 0};
6645 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6646 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6647 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6648 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6650 switch (filter) {
6651 case WINED3DTEXF_LINEAR:
6652 gl_filter = GL_LINEAR;
6653 break;
6655 default:
6656 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6657 case WINED3DTEXF_NONE:
6658 case WINED3DTEXF_POINT:
6659 gl_filter = GL_NEAREST;
6660 break;
6663 /* Attach src surface to src fbo */
6664 src_swapchain = get_swapchain(src_surface);
6665 if (src_swapchain) {
6666 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6668 TRACE("Source surface %p is onscreen\n", src_surface);
6669 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6670 /* Make sure the drawable is up to date. In the offscreen case
6671 * attach_surface_fbo() implicitly takes care of this. */
6672 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6674 if(buffer == GL_FRONT) {
6675 RECT windowsize;
6676 UINT h;
6677 ClientToScreen(This->ddraw_window, &offset);
6678 GetClientRect(This->ddraw_window, &windowsize);
6679 h = windowsize.bottom - windowsize.top;
6680 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6681 src_rect->y1 = offset.y + h - src_rect->y1;
6682 src_rect->y2 = offset.y + h - src_rect->y2;
6683 } else {
6684 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6685 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6688 ENTER_GL();
6689 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6690 glReadBuffer(buffer);
6691 checkGLcall("glReadBuffer()");
6692 } else {
6693 TRACE("Source surface %p is offscreen\n", src_surface);
6694 ENTER_GL();
6695 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->src_fbo);
6696 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6697 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6698 checkGLcall("glReadBuffer()");
6699 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6700 checkGLcall("glFramebufferRenderbufferEXT");
6702 LEAVE_GL();
6704 /* Attach dst surface to dst fbo */
6705 dst_swapchain = get_swapchain(dst_surface);
6706 if (dst_swapchain) {
6707 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6709 TRACE("Destination surface %p is onscreen\n", dst_surface);
6710 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6711 /* Make sure the drawable is up to date. In the offscreen case
6712 * attach_surface_fbo() implicitly takes care of this. */
6713 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6715 if(buffer == GL_FRONT) {
6716 RECT windowsize;
6717 UINT h;
6718 ClientToScreen(This->ddraw_window, &offset);
6719 GetClientRect(This->ddraw_window, &windowsize);
6720 h = windowsize.bottom - windowsize.top;
6721 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6722 dst_rect->y1 = offset.y + h - dst_rect->y1;
6723 dst_rect->y2 = offset.y + h - dst_rect->y2;
6724 } else {
6725 /* Screen coords = window coords, surface height = window height */
6726 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6727 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6730 ENTER_GL();
6731 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6732 glDrawBuffer(buffer);
6733 checkGLcall("glDrawBuffer()");
6734 } else {
6735 TRACE("Destination surface %p is offscreen\n", dst_surface);
6737 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6738 if(!src_swapchain) {
6739 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6742 ENTER_GL();
6743 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->dst_fbo);
6744 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6745 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6746 checkGLcall("glDrawBuffer()");
6747 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6748 checkGLcall("glFramebufferRenderbufferEXT");
6750 glDisable(GL_SCISSOR_TEST);
6751 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6753 if (flip) {
6754 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6755 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6756 checkGLcall("glBlitFramebuffer()");
6757 } else {
6758 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6759 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6760 checkGLcall("glBlitFramebuffer()");
6763 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6765 if (This->render_offscreen) {
6766 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
6767 } else {
6768 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6769 checkGLcall("glBindFramebuffer()");
6772 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6773 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6774 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6775 glDrawBuffer(GL_BACK);
6776 checkGLcall("glDrawBuffer()");
6778 LEAVE_GL();
6781 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6782 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6783 WINED3DVIEWPORT viewport;
6785 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6787 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6788 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6789 This, RenderTargetIndex, GL_LIMITS(buffers));
6790 return WINED3DERR_INVALIDCALL;
6793 /* MSDN says that null disables the render target
6794 but a device must always be associated with a render target
6795 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6797 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6798 FIXME("Trying to set render target 0 to NULL\n");
6799 return WINED3DERR_INVALIDCALL;
6801 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6802 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);
6803 return WINED3DERR_INVALIDCALL;
6806 /* If we are trying to set what we already have, don't bother */
6807 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6808 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6809 return WINED3D_OK;
6811 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6812 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6813 This->render_targets[RenderTargetIndex] = pRenderTarget;
6815 /* Render target 0 is special */
6816 if(RenderTargetIndex == 0) {
6817 /* Finally, reset the viewport as the MSDN states. */
6818 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6819 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6820 viewport.X = 0;
6821 viewport.Y = 0;
6822 viewport.MaxZ = 1.0f;
6823 viewport.MinZ = 0.0f;
6824 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6825 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6826 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6828 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6830 return WINED3D_OK;
6833 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6834 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6835 HRESULT hr = WINED3D_OK;
6836 IWineD3DSurface *tmp;
6838 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6840 if (pNewZStencil == This->stencilBufferTarget) {
6841 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6842 } else {
6843 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6844 * depending on the renter target implementation being used.
6845 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6846 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6847 * stencil buffer and incur an extra memory overhead
6848 ******************************************************/
6850 if (This->stencilBufferTarget) {
6851 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6852 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6853 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6856 tmp = This->stencilBufferTarget;
6857 This->stencilBufferTarget = pNewZStencil;
6858 /* should we be calling the parent or the wined3d surface? */
6859 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6860 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6861 hr = WINED3D_OK;
6863 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6864 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6865 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6866 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6867 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6871 return hr;
6874 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6875 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6876 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6877 /* TODO: the use of Impl is deprecated. */
6878 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6879 WINED3DLOCKED_RECT lockedRect;
6881 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6883 /* some basic validation checks */
6884 if(This->cursorTexture) {
6885 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6886 ENTER_GL();
6887 glDeleteTextures(1, &This->cursorTexture);
6888 LEAVE_GL();
6889 This->cursorTexture = 0;
6892 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6893 This->haveHardwareCursor = TRUE;
6894 else
6895 This->haveHardwareCursor = FALSE;
6897 if(pCursorBitmap) {
6898 WINED3DLOCKED_RECT rect;
6900 /* MSDN: Cursor must be A8R8G8B8 */
6901 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6902 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6903 return WINED3DERR_INVALIDCALL;
6906 /* MSDN: Cursor must be smaller than the display mode */
6907 if(pSur->currentDesc.Width > This->ddraw_width ||
6908 pSur->currentDesc.Height > This->ddraw_height) {
6909 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);
6910 return WINED3DERR_INVALIDCALL;
6913 if (!This->haveHardwareCursor) {
6914 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6916 /* Do not store the surface's pointer because the application may
6917 * release it after setting the cursor image. Windows doesn't
6918 * addref the set surface, so we can't do this either without
6919 * creating circular refcount dependencies. Copy out the gl texture
6920 * instead.
6922 This->cursorWidth = pSur->currentDesc.Width;
6923 This->cursorHeight = pSur->currentDesc.Height;
6924 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6926 const GlPixelFormatDesc *glDesc;
6927 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6928 char *mem, *bits = (char *)rect.pBits;
6929 GLint intfmt = glDesc->glInternal;
6930 GLint format = glDesc->glFormat;
6931 GLint type = glDesc->glType;
6932 INT height = This->cursorHeight;
6933 INT width = This->cursorWidth;
6934 INT bpp = tableEntry->bpp;
6935 INT i, sampler;
6937 /* Reformat the texture memory (pitch and width can be
6938 * different) */
6939 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6940 for(i = 0; i < height; i++)
6941 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6942 IWineD3DSurface_UnlockRect(pCursorBitmap);
6943 ENTER_GL();
6945 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6946 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6947 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6950 /* Make sure that a proper texture unit is selected */
6951 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6952 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6953 checkGLcall("glActiveTextureARB");
6955 sampler = This->rev_tex_unit_map[0];
6956 if (sampler != -1) {
6957 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6959 /* Create a new cursor texture */
6960 glGenTextures(1, &This->cursorTexture);
6961 checkGLcall("glGenTextures");
6962 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6963 checkGLcall("glBindTexture");
6964 /* Copy the bitmap memory into the cursor texture */
6965 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6966 HeapFree(GetProcessHeap(), 0, mem);
6967 checkGLcall("glTexImage2D");
6969 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6970 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6971 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6974 LEAVE_GL();
6976 else
6978 FIXME("A cursor texture was not returned.\n");
6979 This->cursorTexture = 0;
6982 else
6984 /* Draw a hardware cursor */
6985 ICONINFO cursorInfo;
6986 HCURSOR cursor;
6987 /* Create and clear maskBits because it is not needed for
6988 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
6989 * chunks. */
6990 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
6991 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
6992 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
6993 WINED3DLOCK_NO_DIRTY_UPDATE |
6994 WINED3DLOCK_READONLY
6996 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
6997 pSur->currentDesc.Height);
6999 cursorInfo.fIcon = FALSE;
7000 cursorInfo.xHotspot = XHotSpot;
7001 cursorInfo.yHotspot = YHotSpot;
7002 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7003 pSur->currentDesc.Height, 1,
7004 1, &maskBits);
7005 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7006 pSur->currentDesc.Height, 1,
7007 32, lockedRect.pBits);
7008 IWineD3DSurface_UnlockRect(pCursorBitmap);
7009 /* Create our cursor and clean up. */
7010 cursor = CreateIconIndirect(&cursorInfo);
7011 SetCursor(cursor);
7012 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7013 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7014 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7015 This->hardwareCursor = cursor;
7016 HeapFree(GetProcessHeap(), 0, maskBits);
7020 This->xHotSpot = XHotSpot;
7021 This->yHotSpot = YHotSpot;
7022 return WINED3D_OK;
7025 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7026 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7027 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7029 This->xScreenSpace = XScreenSpace;
7030 This->yScreenSpace = YScreenSpace;
7032 return;
7036 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7037 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7038 BOOL oldVisible = This->bCursorVisible;
7039 POINT pt;
7041 TRACE("(%p) : visible(%d)\n", This, bShow);
7044 * When ShowCursor is first called it should make the cursor appear at the OS's last
7045 * known cursor position. Because of this, some applications just repetitively call
7046 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7048 GetCursorPos(&pt);
7049 This->xScreenSpace = pt.x;
7050 This->yScreenSpace = pt.y;
7052 if (This->haveHardwareCursor) {
7053 This->bCursorVisible = bShow;
7054 if (bShow)
7055 SetCursor(This->hardwareCursor);
7056 else
7057 SetCursor(NULL);
7059 else
7061 if (This->cursorTexture)
7062 This->bCursorVisible = bShow;
7065 return oldVisible;
7068 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7069 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7070 IWineD3DResourceImpl *resource;
7071 TRACE("(%p) : state (%u)\n", This, This->state);
7073 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7074 switch (This->state) {
7075 case WINED3D_OK:
7076 return WINED3D_OK;
7077 case WINED3DERR_DEVICELOST:
7079 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7080 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7081 return WINED3DERR_DEVICENOTRESET;
7083 return WINED3DERR_DEVICELOST;
7085 case WINED3DERR_DRIVERINTERNALERROR:
7086 return WINED3DERR_DRIVERINTERNALERROR;
7089 /* Unknown state */
7090 return WINED3DERR_DRIVERINTERNALERROR;
7094 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7095 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7096 /** FIXME: Resource tracking needs to be done,
7097 * The closes we can do to this is set the priorities of all managed textures low
7098 * and then reset them.
7099 ***********************************************************/
7100 FIXME("(%p) : stub\n", This);
7101 return WINED3D_OK;
7104 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7105 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7107 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7108 if(surface->Flags & SFLAG_DIBSECTION) {
7109 /* Release the DC */
7110 SelectObject(surface->hDC, surface->dib.holdbitmap);
7111 DeleteDC(surface->hDC);
7112 /* Release the DIB section */
7113 DeleteObject(surface->dib.DIBsection);
7114 surface->dib.bitmap_data = NULL;
7115 surface->resource.allocatedMemory = NULL;
7116 surface->Flags &= ~SFLAG_DIBSECTION;
7118 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7119 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7120 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7121 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7122 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7123 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7124 } else {
7125 surface->pow2Width = surface->pow2Height = 1;
7126 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7127 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7129 surface->glRect.left = 0;
7130 surface->glRect.top = 0;
7131 surface->glRect.right = surface->pow2Width;
7132 surface->glRect.bottom = surface->pow2Height;
7134 if(surface->glDescription.textureName) {
7135 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7136 ENTER_GL();
7137 glDeleteTextures(1, &surface->glDescription.textureName);
7138 LEAVE_GL();
7139 surface->glDescription.textureName = 0;
7140 surface->Flags &= ~SFLAG_CLIENT;
7142 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7143 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7144 surface->Flags |= SFLAG_NONPOW2;
7145 } else {
7146 surface->Flags &= ~SFLAG_NONPOW2;
7148 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7149 surface->resource.allocatedMemory = NULL;
7150 surface->resource.heapMemory = NULL;
7151 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7152 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7153 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7154 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7155 } else {
7156 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7160 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7161 TRACE("Unloading resource %p\n", resource);
7162 IWineD3DResource_UnLoad(resource);
7163 IWineD3DResource_Release(resource);
7164 return S_OK;
7167 static void reset_fbo_state(IWineD3DDevice *iface) {
7168 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7169 unsigned int i;
7171 ENTER_GL();
7172 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
7173 checkGLcall("glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0)");
7175 if (This->fbo) {
7176 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->fbo));
7177 This->fbo = 0;
7179 if (This->src_fbo) {
7180 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->src_fbo));
7181 This->src_fbo = 0;
7183 if (This->dst_fbo) {
7184 GL_EXTCALL(glDeleteFramebuffersEXT(1, &This->dst_fbo));
7185 This->dst_fbo = 0;
7187 checkGLcall("Tear down FBOs\n");
7188 LEAVE_GL();
7190 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7191 This->fbo_color_attachments[i] = NULL;
7193 This->fbo_depth_attachment = NULL;
7196 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7197 UINT i, count;
7198 WINED3DDISPLAYMODE m;
7199 HRESULT hr;
7201 /* All Windowed modes are supported, as is leaving the current mode */
7202 if(pp->Windowed) return TRUE;
7203 if(!pp->BackBufferWidth) return TRUE;
7204 if(!pp->BackBufferHeight) return TRUE;
7206 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7207 for(i = 0; i < count; i++) {
7208 memset(&m, 0, sizeof(m));
7209 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7210 if(FAILED(hr)) {
7211 ERR("EnumAdapterModes failed\n");
7213 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7214 /* Mode found, it is supported */
7215 return TRUE;
7218 /* Mode not found -> not supported */
7219 return FALSE;
7222 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7223 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7224 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7225 UINT i;
7226 IWineD3DBaseShaderImpl *shader;
7228 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
7229 reset_fbo_state((IWineD3DDevice *) This);
7232 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7233 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7234 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7237 ENTER_GL();
7238 if(This->depth_blt_texture) {
7239 glDeleteTextures(1, &This->depth_blt_texture);
7240 This->depth_blt_texture = 0;
7242 if (This->depth_blt_rb) {
7243 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7244 This->depth_blt_rb = 0;
7245 This->depth_blt_rb_w = 0;
7246 This->depth_blt_rb_h = 0;
7248 This->frag_pipe->free_private(iface);
7249 This->shader_backend->shader_free_private(iface);
7251 for (i = 0; i < GL_LIMITS(textures); i++) {
7252 /* Textures are recreated below */
7253 glDeleteTextures(1, &This->dummyTextureName[i]);
7254 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7255 This->dummyTextureName[i] = 0;
7257 LEAVE_GL();
7259 while(This->numContexts) {
7260 DestroyContext(This, This->contexts[0]);
7262 This->activeContext = NULL;
7263 HeapFree(GetProcessHeap(), 0, swapchain->context);
7264 swapchain->context = NULL;
7265 swapchain->num_contexts = 0;
7268 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7269 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7270 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7271 HRESULT hr;
7272 IWineD3DSurfaceImpl *target;
7274 /* Recreate the primary swapchain's context */
7275 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7276 if(swapchain->backBuffer) {
7277 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7278 } else {
7279 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7281 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7282 &swapchain->presentParms);
7283 swapchain->num_contexts = 1;
7284 This->activeContext = swapchain->context[0];
7286 create_dummy_textures(This);
7288 hr = This->shader_backend->shader_alloc_private(iface);
7289 if(FAILED(hr)) {
7290 ERR("Failed to recreate shader private data\n");
7291 return hr;
7293 hr = This->frag_pipe->alloc_private(iface);
7294 if(FAILED(hr)) {
7295 TRACE("Fragment pipeline private data couldn't be allocated\n");
7296 return hr;
7299 return WINED3D_OK;
7302 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7303 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7304 IWineD3DSwapChainImpl *swapchain;
7305 HRESULT hr;
7306 BOOL DisplayModeChanged = FALSE;
7307 WINED3DDISPLAYMODE mode;
7308 TRACE("(%p)\n", This);
7310 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7311 if(FAILED(hr)) {
7312 ERR("Failed to get the first implicit swapchain\n");
7313 return hr;
7316 if(!is_display_mode_supported(This, pPresentationParameters)) {
7317 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7318 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7319 pPresentationParameters->BackBufferHeight);
7320 return WINED3DERR_INVALIDCALL;
7323 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7324 * on an existing gl context, so there's no real need for recreation.
7326 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7328 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7330 TRACE("New params:\n");
7331 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7332 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7333 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7334 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7335 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7336 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7337 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7338 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7339 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7340 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7341 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7342 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7343 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7345 /* No special treatment of these parameters. Just store them */
7346 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7347 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7348 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7349 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7351 /* What to do about these? */
7352 if(pPresentationParameters->BackBufferCount != 0 &&
7353 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7354 ERR("Cannot change the back buffer count yet\n");
7356 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7357 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7358 ERR("Cannot change the back buffer format yet\n");
7360 if(pPresentationParameters->hDeviceWindow != NULL &&
7361 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7362 ERR("Cannot change the device window yet\n");
7364 if(pPresentationParameters->EnableAutoDepthStencil != swapchain->presentParms.EnableAutoDepthStencil) {
7365 ERR("What do do about a changed auto depth stencil parameter?\n");
7368 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7370 if(pPresentationParameters->Windowed) {
7371 mode.Width = swapchain->orig_width;
7372 mode.Height = swapchain->orig_height;
7373 mode.RefreshRate = 0;
7374 mode.Format = swapchain->presentParms.BackBufferFormat;
7375 } else {
7376 mode.Width = pPresentationParameters->BackBufferWidth;
7377 mode.Height = pPresentationParameters->BackBufferHeight;
7378 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7379 mode.Format = swapchain->presentParms.BackBufferFormat;
7382 /* Should Width == 800 && Height == 0 set 800x600? */
7383 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7384 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7385 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7387 WINED3DVIEWPORT vp;
7388 int i;
7390 vp.X = 0;
7391 vp.Y = 0;
7392 vp.Width = pPresentationParameters->BackBufferWidth;
7393 vp.Height = pPresentationParameters->BackBufferHeight;
7394 vp.MinZ = 0;
7395 vp.MaxZ = 1;
7397 if(!pPresentationParameters->Windowed) {
7398 DisplayModeChanged = TRUE;
7400 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7401 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7403 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7404 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7405 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7407 if(This->auto_depth_stencil_buffer) {
7408 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7412 /* Now set the new viewport */
7413 IWineD3DDevice_SetViewport(iface, &vp);
7416 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7417 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7418 DisplayModeChanged) {
7420 IWineD3DDevice_SetFullscreen(iface, !pPresentationParameters->Windowed);
7421 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7422 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7423 } else if(!pPresentationParameters->Windowed) {
7424 DWORD style = This->style, exStyle = This->exStyle;
7425 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7426 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7427 * Reset to clear up their mess. Guild Wars also loses the device during that.
7429 This->style = 0;
7430 This->exStyle = 0;
7431 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, This->ddraw_window);
7432 This->style = style;
7433 This->exStyle = exStyle;
7436 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7437 if(FAILED(hr)) {
7438 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7441 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7442 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7444 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7445 * first use
7447 return hr;
7450 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7452 /** FIXME: always true at the moment **/
7453 if(!bEnableDialogs) {
7454 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7456 return WINED3D_OK;
7460 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7462 TRACE("(%p) : pParameters %p\n", This, pParameters);
7464 *pParameters = This->createParms;
7465 return WINED3D_OK;
7468 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7469 IWineD3DSwapChain *swapchain;
7471 TRACE("Relaying to swapchain\n");
7473 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7474 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7475 IWineD3DSwapChain_Release(swapchain);
7477 return;
7480 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7481 IWineD3DSwapChain *swapchain;
7483 TRACE("Relaying to swapchain\n");
7485 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7486 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7487 IWineD3DSwapChain_Release(swapchain);
7489 return;
7493 /** ********************************************************
7494 * Notification functions
7495 ** ********************************************************/
7496 /** This function must be called in the release of a resource when ref == 0,
7497 * the contents of resource must still be correct,
7498 * any handles to other resource held by the caller must be closed
7499 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7500 *****************************************************/
7501 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7502 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7504 TRACE("(%p) : Adding Resource %p\n", This, resource);
7505 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7508 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7509 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7511 TRACE("(%p) : Removing resource %p\n", This, resource);
7513 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7517 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7518 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7519 int counter;
7521 TRACE("(%p) : resource %p\n", This, resource);
7522 switch(IWineD3DResource_GetType(resource)){
7523 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7524 case WINED3DRTYPE_SURFACE: {
7525 unsigned int i;
7527 /* Cleanup any FBO attachments if d3d is enabled */
7528 if(This->d3d_initialized) {
7529 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7530 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7532 TRACE("Last active render target destroyed\n");
7533 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7534 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7535 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7536 * and the lastActiveRenderTarget member shouldn't matter
7538 if(swapchain) {
7539 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7540 TRACE("Activating primary back buffer\n");
7541 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7542 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7543 /* Single buffering environment */
7544 TRACE("Activating primary front buffer\n");
7545 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7546 } else {
7547 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7548 /* Implicit render target destroyed, that means the device is being destroyed
7549 * whatever we set here, it shouldn't matter
7551 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7553 } else {
7554 /* May happen during ddraw uninitialization */
7555 TRACE("Render target set, but swapchain does not exist!\n");
7556 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7560 ENTER_GL();
7561 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7562 if (This->fbo_color_attachments[i] == (IWineD3DSurface *)resource) {
7563 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7564 set_render_target_fbo(iface, i, NULL);
7565 This->fbo_color_attachments[i] = NULL;
7568 if (This->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7569 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->fbo);
7570 set_depth_stencil_fbo(iface, NULL);
7571 This->fbo_depth_attachment = NULL;
7573 LEAVE_GL();
7576 break;
7578 case WINED3DRTYPE_TEXTURE:
7579 case WINED3DRTYPE_CUBETEXTURE:
7580 case WINED3DRTYPE_VOLUMETEXTURE:
7581 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7582 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7583 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7584 This->stateBlock->textures[counter] = NULL;
7586 if (This->updateStateBlock != This->stateBlock ){
7587 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7588 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7589 This->updateStateBlock->textures[counter] = NULL;
7593 break;
7594 case WINED3DRTYPE_VOLUME:
7595 /* TODO: nothing really? */
7596 break;
7597 case WINED3DRTYPE_VERTEXBUFFER:
7598 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7600 int streamNumber;
7601 TRACE("Cleaning up stream pointers\n");
7603 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7604 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7605 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7607 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7608 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7609 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7610 This->updateStateBlock->streamSource[streamNumber] = 0;
7611 /* Set changed flag? */
7614 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) */
7615 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7616 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7617 This->stateBlock->streamSource[streamNumber] = 0;
7620 #if 0 /* TODO: Manage internal tracking properly so that 'this shouldn't happen' */
7621 else { /* This shouldn't happen */
7622 FIXME("Calling application has released the device before relasing all the resources bound to the device\n");
7624 #endif
7628 break;
7629 case WINED3DRTYPE_INDEXBUFFER:
7630 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7631 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7632 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7633 This->updateStateBlock->pIndexData = NULL;
7636 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7637 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7638 This->stateBlock->pIndexData = NULL;
7642 break;
7643 default:
7644 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7645 break;
7649 /* Remove the resource from the resourceStore */
7650 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7652 TRACE("Resource released\n");
7656 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7657 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7658 IWineD3DResourceImpl *resource, *cursor;
7659 HRESULT ret;
7660 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7662 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7663 TRACE("enumerating resource %p\n", resource);
7664 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7665 ret = pCallback((IWineD3DResource *) resource, pData);
7666 if(ret == S_FALSE) {
7667 TRACE("Canceling enumeration\n");
7668 break;
7671 return WINED3D_OK;
7674 /**********************************************************
7675 * IWineD3DDevice VTbl follows
7676 **********************************************************/
7678 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7680 /*** IUnknown methods ***/
7681 IWineD3DDeviceImpl_QueryInterface,
7682 IWineD3DDeviceImpl_AddRef,
7683 IWineD3DDeviceImpl_Release,
7684 /*** IWineD3DDevice methods ***/
7685 IWineD3DDeviceImpl_GetParent,
7686 /*** Creation methods**/
7687 IWineD3DDeviceImpl_CreateVertexBuffer,
7688 IWineD3DDeviceImpl_CreateIndexBuffer,
7689 IWineD3DDeviceImpl_CreateStateBlock,
7690 IWineD3DDeviceImpl_CreateSurface,
7691 IWineD3DDeviceImpl_CreateTexture,
7692 IWineD3DDeviceImpl_CreateVolumeTexture,
7693 IWineD3DDeviceImpl_CreateVolume,
7694 IWineD3DDeviceImpl_CreateCubeTexture,
7695 IWineD3DDeviceImpl_CreateQuery,
7696 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7697 IWineD3DDeviceImpl_CreateVertexDeclaration,
7698 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7699 IWineD3DDeviceImpl_CreateVertexShader,
7700 IWineD3DDeviceImpl_CreatePixelShader,
7701 IWineD3DDeviceImpl_CreatePalette,
7702 /*** Odd functions **/
7703 IWineD3DDeviceImpl_Init3D,
7704 IWineD3DDeviceImpl_InitGDI,
7705 IWineD3DDeviceImpl_Uninit3D,
7706 IWineD3DDeviceImpl_UninitGDI,
7707 IWineD3DDeviceImpl_SetFullscreen,
7708 IWineD3DDeviceImpl_SetMultithreaded,
7709 IWineD3DDeviceImpl_EvictManagedResources,
7710 IWineD3DDeviceImpl_GetAvailableTextureMem,
7711 IWineD3DDeviceImpl_GetBackBuffer,
7712 IWineD3DDeviceImpl_GetCreationParameters,
7713 IWineD3DDeviceImpl_GetDeviceCaps,
7714 IWineD3DDeviceImpl_GetDirect3D,
7715 IWineD3DDeviceImpl_GetDisplayMode,
7716 IWineD3DDeviceImpl_SetDisplayMode,
7717 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7718 IWineD3DDeviceImpl_GetRasterStatus,
7719 IWineD3DDeviceImpl_GetSwapChain,
7720 IWineD3DDeviceImpl_Reset,
7721 IWineD3DDeviceImpl_SetDialogBoxMode,
7722 IWineD3DDeviceImpl_SetCursorProperties,
7723 IWineD3DDeviceImpl_SetCursorPosition,
7724 IWineD3DDeviceImpl_ShowCursor,
7725 IWineD3DDeviceImpl_TestCooperativeLevel,
7726 /*** Getters and setters **/
7727 IWineD3DDeviceImpl_SetClipPlane,
7728 IWineD3DDeviceImpl_GetClipPlane,
7729 IWineD3DDeviceImpl_SetClipStatus,
7730 IWineD3DDeviceImpl_GetClipStatus,
7731 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7732 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7733 IWineD3DDeviceImpl_SetDepthStencilSurface,
7734 IWineD3DDeviceImpl_GetDepthStencilSurface,
7735 IWineD3DDeviceImpl_SetFVF,
7736 IWineD3DDeviceImpl_GetFVF,
7737 IWineD3DDeviceImpl_SetGammaRamp,
7738 IWineD3DDeviceImpl_GetGammaRamp,
7739 IWineD3DDeviceImpl_SetIndices,
7740 IWineD3DDeviceImpl_GetIndices,
7741 IWineD3DDeviceImpl_SetBaseVertexIndex,
7742 IWineD3DDeviceImpl_GetBaseVertexIndex,
7743 IWineD3DDeviceImpl_SetLight,
7744 IWineD3DDeviceImpl_GetLight,
7745 IWineD3DDeviceImpl_SetLightEnable,
7746 IWineD3DDeviceImpl_GetLightEnable,
7747 IWineD3DDeviceImpl_SetMaterial,
7748 IWineD3DDeviceImpl_GetMaterial,
7749 IWineD3DDeviceImpl_SetNPatchMode,
7750 IWineD3DDeviceImpl_GetNPatchMode,
7751 IWineD3DDeviceImpl_SetPaletteEntries,
7752 IWineD3DDeviceImpl_GetPaletteEntries,
7753 IWineD3DDeviceImpl_SetPixelShader,
7754 IWineD3DDeviceImpl_GetPixelShader,
7755 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7756 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7757 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7758 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7759 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7760 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7761 IWineD3DDeviceImpl_SetRenderState,
7762 IWineD3DDeviceImpl_GetRenderState,
7763 IWineD3DDeviceImpl_SetRenderTarget,
7764 IWineD3DDeviceImpl_GetRenderTarget,
7765 IWineD3DDeviceImpl_SetFrontBackBuffers,
7766 IWineD3DDeviceImpl_SetSamplerState,
7767 IWineD3DDeviceImpl_GetSamplerState,
7768 IWineD3DDeviceImpl_SetScissorRect,
7769 IWineD3DDeviceImpl_GetScissorRect,
7770 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7771 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7772 IWineD3DDeviceImpl_SetStreamSource,
7773 IWineD3DDeviceImpl_GetStreamSource,
7774 IWineD3DDeviceImpl_SetStreamSourceFreq,
7775 IWineD3DDeviceImpl_GetStreamSourceFreq,
7776 IWineD3DDeviceImpl_SetTexture,
7777 IWineD3DDeviceImpl_GetTexture,
7778 IWineD3DDeviceImpl_SetTextureStageState,
7779 IWineD3DDeviceImpl_GetTextureStageState,
7780 IWineD3DDeviceImpl_SetTransform,
7781 IWineD3DDeviceImpl_GetTransform,
7782 IWineD3DDeviceImpl_SetVertexDeclaration,
7783 IWineD3DDeviceImpl_GetVertexDeclaration,
7784 IWineD3DDeviceImpl_SetVertexShader,
7785 IWineD3DDeviceImpl_GetVertexShader,
7786 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7787 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7788 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7789 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7790 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7791 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7792 IWineD3DDeviceImpl_SetViewport,
7793 IWineD3DDeviceImpl_GetViewport,
7794 IWineD3DDeviceImpl_MultiplyTransform,
7795 IWineD3DDeviceImpl_ValidateDevice,
7796 IWineD3DDeviceImpl_ProcessVertices,
7797 /*** State block ***/
7798 IWineD3DDeviceImpl_BeginStateBlock,
7799 IWineD3DDeviceImpl_EndStateBlock,
7800 /*** Scene management ***/
7801 IWineD3DDeviceImpl_BeginScene,
7802 IWineD3DDeviceImpl_EndScene,
7803 IWineD3DDeviceImpl_Present,
7804 IWineD3DDeviceImpl_Clear,
7805 /*** Drawing ***/
7806 IWineD3DDeviceImpl_DrawPrimitive,
7807 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7808 IWineD3DDeviceImpl_DrawPrimitiveUP,
7809 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7810 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7811 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7812 IWineD3DDeviceImpl_DrawRectPatch,
7813 IWineD3DDeviceImpl_DrawTriPatch,
7814 IWineD3DDeviceImpl_DeletePatch,
7815 IWineD3DDeviceImpl_ColorFill,
7816 IWineD3DDeviceImpl_UpdateTexture,
7817 IWineD3DDeviceImpl_UpdateSurface,
7818 IWineD3DDeviceImpl_GetFrontBufferData,
7819 /*** object tracking ***/
7820 IWineD3DDeviceImpl_ResourceReleased,
7821 IWineD3DDeviceImpl_EnumResources
7824 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7826 /*** IUnknown methods ***/
7827 IWineD3DDeviceImpl_QueryInterface,
7828 IWineD3DDeviceImpl_AddRef,
7829 IWineD3DDeviceImpl_Release,
7830 /*** IWineD3DDevice methods ***/
7831 IWineD3DDeviceImpl_GetParent,
7832 /*** Creation methods**/
7833 IWineD3DDeviceImpl_CreateVertexBuffer,
7834 IWineD3DDeviceImpl_CreateIndexBuffer,
7835 IWineD3DDeviceImpl_CreateStateBlock,
7836 IWineD3DDeviceImpl_CreateSurface,
7837 IWineD3DDeviceImpl_CreateTexture,
7838 IWineD3DDeviceImpl_CreateVolumeTexture,
7839 IWineD3DDeviceImpl_CreateVolume,
7840 IWineD3DDeviceImpl_CreateCubeTexture,
7841 IWineD3DDeviceImpl_CreateQuery,
7842 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7843 IWineD3DDeviceImpl_CreateVertexDeclaration,
7844 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7845 IWineD3DDeviceImpl_CreateVertexShader,
7846 IWineD3DDeviceImpl_CreatePixelShader,
7847 IWineD3DDeviceImpl_CreatePalette,
7848 /*** Odd functions **/
7849 IWineD3DDeviceImpl_Init3D,
7850 IWineD3DDeviceImpl_InitGDI,
7851 IWineD3DDeviceImpl_Uninit3D,
7852 IWineD3DDeviceImpl_UninitGDI,
7853 IWineD3DDeviceImpl_SetFullscreen,
7854 IWineD3DDeviceImpl_SetMultithreaded,
7855 IWineD3DDeviceImpl_EvictManagedResources,
7856 IWineD3DDeviceImpl_GetAvailableTextureMem,
7857 IWineD3DDeviceImpl_GetBackBuffer,
7858 IWineD3DDeviceImpl_GetCreationParameters,
7859 IWineD3DDeviceImpl_GetDeviceCaps,
7860 IWineD3DDeviceImpl_GetDirect3D,
7861 IWineD3DDeviceImpl_GetDisplayMode,
7862 IWineD3DDeviceImpl_SetDisplayMode,
7863 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7864 IWineD3DDeviceImpl_GetRasterStatus,
7865 IWineD3DDeviceImpl_GetSwapChain,
7866 IWineD3DDeviceImpl_Reset,
7867 IWineD3DDeviceImpl_SetDialogBoxMode,
7868 IWineD3DDeviceImpl_SetCursorProperties,
7869 IWineD3DDeviceImpl_SetCursorPosition,
7870 IWineD3DDeviceImpl_ShowCursor,
7871 IWineD3DDeviceImpl_TestCooperativeLevel,
7872 /*** Getters and setters **/
7873 IWineD3DDeviceImpl_SetClipPlane,
7874 IWineD3DDeviceImpl_GetClipPlane,
7875 IWineD3DDeviceImpl_SetClipStatus,
7876 IWineD3DDeviceImpl_GetClipStatus,
7877 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7878 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7879 IWineD3DDeviceImpl_SetDepthStencilSurface,
7880 IWineD3DDeviceImpl_GetDepthStencilSurface,
7881 IWineD3DDeviceImpl_SetFVF,
7882 IWineD3DDeviceImpl_GetFVF,
7883 IWineD3DDeviceImpl_SetGammaRamp,
7884 IWineD3DDeviceImpl_GetGammaRamp,
7885 IWineD3DDeviceImpl_SetIndices,
7886 IWineD3DDeviceImpl_GetIndices,
7887 IWineD3DDeviceImpl_SetBaseVertexIndex,
7888 IWineD3DDeviceImpl_GetBaseVertexIndex,
7889 IWineD3DDeviceImpl_SetLight,
7890 IWineD3DDeviceImpl_GetLight,
7891 IWineD3DDeviceImpl_SetLightEnable,
7892 IWineD3DDeviceImpl_GetLightEnable,
7893 IWineD3DDeviceImpl_SetMaterial,
7894 IWineD3DDeviceImpl_GetMaterial,
7895 IWineD3DDeviceImpl_SetNPatchMode,
7896 IWineD3DDeviceImpl_GetNPatchMode,
7897 IWineD3DDeviceImpl_SetPaletteEntries,
7898 IWineD3DDeviceImpl_GetPaletteEntries,
7899 IWineD3DDeviceImpl_SetPixelShader,
7900 IWineD3DDeviceImpl_GetPixelShader,
7901 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7902 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7903 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7904 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7905 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7906 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7907 IWineD3DDeviceImpl_SetRenderState,
7908 IWineD3DDeviceImpl_GetRenderState,
7909 IWineD3DDeviceImpl_SetRenderTarget,
7910 IWineD3DDeviceImpl_GetRenderTarget,
7911 IWineD3DDeviceImpl_SetFrontBackBuffers,
7912 IWineD3DDeviceImpl_SetSamplerState,
7913 IWineD3DDeviceImpl_GetSamplerState,
7914 IWineD3DDeviceImpl_SetScissorRect,
7915 IWineD3DDeviceImpl_GetScissorRect,
7916 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7917 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7918 IWineD3DDeviceImpl_SetStreamSource,
7919 IWineD3DDeviceImpl_GetStreamSource,
7920 IWineD3DDeviceImpl_SetStreamSourceFreq,
7921 IWineD3DDeviceImpl_GetStreamSourceFreq,
7922 IWineD3DDeviceImpl_SetTexture,
7923 IWineD3DDeviceImpl_GetTexture,
7924 IWineD3DDeviceImpl_SetTextureStageState,
7925 IWineD3DDeviceImpl_GetTextureStageState,
7926 IWineD3DDeviceImpl_SetTransform,
7927 IWineD3DDeviceImpl_GetTransform,
7928 IWineD3DDeviceImpl_SetVertexDeclaration,
7929 IWineD3DDeviceImpl_GetVertexDeclaration,
7930 IWineD3DDeviceImpl_SetVertexShader,
7931 IWineD3DDeviceImpl_GetVertexShader,
7932 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7933 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7934 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7935 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7936 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7937 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7938 IWineD3DDeviceImpl_SetViewport,
7939 IWineD3DDeviceImpl_GetViewport,
7940 IWineD3DDeviceImpl_MultiplyTransform,
7941 IWineD3DDeviceImpl_ValidateDevice,
7942 IWineD3DDeviceImpl_ProcessVertices,
7943 /*** State block ***/
7944 IWineD3DDeviceImpl_BeginStateBlock,
7945 IWineD3DDeviceImpl_EndStateBlock,
7946 /*** Scene management ***/
7947 IWineD3DDeviceImpl_BeginScene,
7948 IWineD3DDeviceImpl_EndScene,
7949 IWineD3DDeviceImpl_Present,
7950 IWineD3DDeviceImpl_Clear,
7951 /*** Drawing ***/
7952 IWineD3DDeviceImpl_DrawPrimitive,
7953 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7954 IWineD3DDeviceImpl_DrawPrimitiveUP,
7955 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7956 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7957 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7958 IWineD3DDeviceImpl_DrawRectPatch,
7959 IWineD3DDeviceImpl_DrawTriPatch,
7960 IWineD3DDeviceImpl_DeletePatch,
7961 IWineD3DDeviceImpl_ColorFill,
7962 IWineD3DDeviceImpl_UpdateTexture,
7963 IWineD3DDeviceImpl_UpdateSurface,
7964 IWineD3DDeviceImpl_GetFrontBufferData,
7965 /*** object tracking ***/
7966 IWineD3DDeviceImpl_ResourceReleased,
7967 IWineD3DDeviceImpl_EnumResources
7970 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7971 WINED3DRS_ALPHABLENDENABLE ,
7972 WINED3DRS_ALPHAFUNC ,
7973 WINED3DRS_ALPHAREF ,
7974 WINED3DRS_ALPHATESTENABLE ,
7975 WINED3DRS_BLENDOP ,
7976 WINED3DRS_COLORWRITEENABLE ,
7977 WINED3DRS_DESTBLEND ,
7978 WINED3DRS_DITHERENABLE ,
7979 WINED3DRS_FILLMODE ,
7980 WINED3DRS_FOGDENSITY ,
7981 WINED3DRS_FOGEND ,
7982 WINED3DRS_FOGSTART ,
7983 WINED3DRS_LASTPIXEL ,
7984 WINED3DRS_SHADEMODE ,
7985 WINED3DRS_SRCBLEND ,
7986 WINED3DRS_STENCILENABLE ,
7987 WINED3DRS_STENCILFAIL ,
7988 WINED3DRS_STENCILFUNC ,
7989 WINED3DRS_STENCILMASK ,
7990 WINED3DRS_STENCILPASS ,
7991 WINED3DRS_STENCILREF ,
7992 WINED3DRS_STENCILWRITEMASK ,
7993 WINED3DRS_STENCILZFAIL ,
7994 WINED3DRS_TEXTUREFACTOR ,
7995 WINED3DRS_WRAP0 ,
7996 WINED3DRS_WRAP1 ,
7997 WINED3DRS_WRAP2 ,
7998 WINED3DRS_WRAP3 ,
7999 WINED3DRS_WRAP4 ,
8000 WINED3DRS_WRAP5 ,
8001 WINED3DRS_WRAP6 ,
8002 WINED3DRS_WRAP7 ,
8003 WINED3DRS_ZENABLE ,
8004 WINED3DRS_ZFUNC ,
8005 WINED3DRS_ZWRITEENABLE
8008 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8009 WINED3DTSS_ADDRESSW ,
8010 WINED3DTSS_ALPHAARG0 ,
8011 WINED3DTSS_ALPHAARG1 ,
8012 WINED3DTSS_ALPHAARG2 ,
8013 WINED3DTSS_ALPHAOP ,
8014 WINED3DTSS_BUMPENVLOFFSET ,
8015 WINED3DTSS_BUMPENVLSCALE ,
8016 WINED3DTSS_BUMPENVMAT00 ,
8017 WINED3DTSS_BUMPENVMAT01 ,
8018 WINED3DTSS_BUMPENVMAT10 ,
8019 WINED3DTSS_BUMPENVMAT11 ,
8020 WINED3DTSS_COLORARG0 ,
8021 WINED3DTSS_COLORARG1 ,
8022 WINED3DTSS_COLORARG2 ,
8023 WINED3DTSS_COLOROP ,
8024 WINED3DTSS_RESULTARG ,
8025 WINED3DTSS_TEXCOORDINDEX ,
8026 WINED3DTSS_TEXTURETRANSFORMFLAGS
8029 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8030 WINED3DSAMP_ADDRESSU ,
8031 WINED3DSAMP_ADDRESSV ,
8032 WINED3DSAMP_ADDRESSW ,
8033 WINED3DSAMP_BORDERCOLOR ,
8034 WINED3DSAMP_MAGFILTER ,
8035 WINED3DSAMP_MINFILTER ,
8036 WINED3DSAMP_MIPFILTER ,
8037 WINED3DSAMP_MIPMAPLODBIAS ,
8038 WINED3DSAMP_MAXMIPLEVEL ,
8039 WINED3DSAMP_MAXANISOTROPY ,
8040 WINED3DSAMP_SRGBTEXTURE ,
8041 WINED3DSAMP_ELEMENTINDEX
8044 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8045 WINED3DRS_AMBIENT ,
8046 WINED3DRS_AMBIENTMATERIALSOURCE ,
8047 WINED3DRS_CLIPPING ,
8048 WINED3DRS_CLIPPLANEENABLE ,
8049 WINED3DRS_COLORVERTEX ,
8050 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8051 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8052 WINED3DRS_FOGDENSITY ,
8053 WINED3DRS_FOGEND ,
8054 WINED3DRS_FOGSTART ,
8055 WINED3DRS_FOGTABLEMODE ,
8056 WINED3DRS_FOGVERTEXMODE ,
8057 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8058 WINED3DRS_LIGHTING ,
8059 WINED3DRS_LOCALVIEWER ,
8060 WINED3DRS_MULTISAMPLEANTIALIAS ,
8061 WINED3DRS_MULTISAMPLEMASK ,
8062 WINED3DRS_NORMALIZENORMALS ,
8063 WINED3DRS_PATCHEDGESTYLE ,
8064 WINED3DRS_POINTSCALE_A ,
8065 WINED3DRS_POINTSCALE_B ,
8066 WINED3DRS_POINTSCALE_C ,
8067 WINED3DRS_POINTSCALEENABLE ,
8068 WINED3DRS_POINTSIZE ,
8069 WINED3DRS_POINTSIZE_MAX ,
8070 WINED3DRS_POINTSIZE_MIN ,
8071 WINED3DRS_POINTSPRITEENABLE ,
8072 WINED3DRS_RANGEFOGENABLE ,
8073 WINED3DRS_SPECULARMATERIALSOURCE ,
8074 WINED3DRS_TWEENFACTOR ,
8075 WINED3DRS_VERTEXBLEND ,
8076 WINED3DRS_CULLMODE ,
8077 WINED3DRS_FOGCOLOR
8080 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8081 WINED3DTSS_TEXCOORDINDEX ,
8082 WINED3DTSS_TEXTURETRANSFORMFLAGS
8085 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8086 WINED3DSAMP_DMAPOFFSET
8089 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8090 DWORD rep = This->StateTable[state].representative;
8091 DWORD idx;
8092 BYTE shift;
8093 UINT i;
8094 WineD3DContext *context;
8096 if(!rep) return;
8097 for(i = 0; i < This->numContexts; i++) {
8098 context = This->contexts[i];
8099 if(isStateDirty(context, rep)) continue;
8101 context->dirtyArray[context->numDirtyEntries++] = rep;
8102 idx = rep >> 5;
8103 shift = rep & 0x1f;
8104 context->isStateDirty[idx] |= (1 << shift);
8108 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8109 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8110 /* The drawable size of a pbuffer render target is the current pbuffer size
8112 *width = dev->pbufferWidth;
8113 *height = dev->pbufferHeight;
8116 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8117 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8119 *width = This->pow2Width;
8120 *height = This->pow2Height;
8123 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8124 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8125 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8126 * current context's drawable, which is the size of the back buffer of the swapchain
8127 * the active context belongs to. The back buffer of the swapchain is stored as the
8128 * surface the context belongs to.
8130 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8131 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;