widl: Don't automatically add DUMMYUNIONNAME and DUMMYSTRUCTNAME names to anonymous...
[wine/multimedia.git] / dlls / wined3d / device.c
blob1c05dc9ab9835aa0fbfe68af6de59232631d2a9f
1 /*
2 * IWineD3DDevice implementation
4 * Copyright 2002 Lionel Ulmer
5 * Copyright 2002-2005 Jason Edmeades
6 * Copyright 2003-2004 Raphael Junqueira
7 * Copyright 2004 Christian Costa
8 * Copyright 2005 Oliver Stieber
9 * Copyright 2006-2008 Stefan Dösinger for CodeWeavers
10 * Copyright 2006-2008 Henri Verbeet
11 * Copyright 2007 Andrew Riedi
13 * This library is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public
15 * License as published by the Free Software Foundation; either
16 * version 2.1 of the License, or (at your option) any later version.
18 * This library is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * Lesser General Public License for more details.
23 * You should have received a copy of the GNU Lesser General Public
24 * License along with this library; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
28 #include "config.h"
29 #include <stdio.h>
30 #ifdef HAVE_FLOAT_H
31 # include <float.h>
32 #endif
33 #include "wined3d_private.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(d3d);
36 #define GLINFO_LOCATION This->adapter->gl_info
38 /* Define the default light parameters as specified by MSDN */
39 const WINED3DLIGHT WINED3D_default_light = {
41 WINED3DLIGHT_DIRECTIONAL, /* Type */
42 { 1.0, 1.0, 1.0, 0.0 }, /* Diffuse r,g,b,a */
43 { 0.0, 0.0, 0.0, 0.0 }, /* Specular r,g,b,a */
44 { 0.0, 0.0, 0.0, 0.0 }, /* Ambient r,g,b,a, */
45 { 0.0, 0.0, 0.0 }, /* Position x,y,z */
46 { 0.0, 0.0, 1.0 }, /* Direction x,y,z */
47 0.0, /* Range */
48 0.0, /* Falloff */
49 0.0, 0.0, 0.0, /* Attenuation 0,1,2 */
50 0.0, /* Theta */
51 0.0 /* Phi */
54 /* static function declarations */
55 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource);
57 /* helper macros */
58 #define D3DMEMCHECK(object, ppResult) if(NULL == object) { *ppResult = NULL; WARN("Out of memory\n"); return WINED3DERR_OUTOFVIDEOMEMORY;}
60 #define D3DCREATEOBJECTINSTANCE(object, type) { \
61 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
62 D3DMEMCHECK(object, pp##type); \
63 object->lpVtbl = &IWineD3D##type##_Vtbl; \
64 object->wineD3DDevice = This; \
65 object->parent = parent; \
66 object->ref = 1; \
67 *pp##type = (IWineD3D##type *) object; \
70 #define D3DCREATESHADEROBJECTINSTANCE(object, type) { \
71 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
72 D3DMEMCHECK(object, pp##type); \
73 object->lpVtbl = &IWineD3D##type##_Vtbl; \
74 object->parent = parent; \
75 object->baseShader.ref = 1; \
76 object->baseShader.device = (IWineD3DDevice*) This; \
77 list_init(&object->baseShader.linked_programs); \
78 *pp##type = (IWineD3D##type *) object; \
81 #define D3DCREATERESOURCEOBJECTINSTANCE(object, type, d3dtype, _size){ \
82 object=HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3D##type##Impl)); \
83 D3DMEMCHECK(object, pp##type); \
84 object->lpVtbl = &IWineD3D##type##_Vtbl; \
85 object->resource.wineD3DDevice = This; \
86 object->resource.parent = parent; \
87 object->resource.resourceType = d3dtype; \
88 object->resource.ref = 1; \
89 object->resource.pool = Pool; \
90 object->resource.format = Format; \
91 object->resource.usage = Usage; \
92 object->resource.size = _size; \
93 list_init(&object->resource.privateData); \
94 /* Check that we have enough video ram left */ \
95 if (Pool == WINED3DPOOL_DEFAULT) { \
96 if (IWineD3DDevice_GetAvailableTextureMem(iface) <= _size) { \
97 WARN("Out of 'bogus' video memory\n"); \
98 HeapFree(GetProcessHeap(), 0, object); \
99 *pp##type = NULL; \
100 return WINED3DERR_OUTOFVIDEOMEMORY; \
102 WineD3DAdapterChangeGLRam(This, _size); \
104 object->resource.heapMemory = (0 == _size ? NULL : HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, _size + RESOURCE_ALIGNMENT)); \
105 if (object->resource.heapMemory == NULL && _size != 0) { \
106 FIXME("Out of memory!\n"); \
107 HeapFree(GetProcessHeap(), 0, object); \
108 *pp##type = NULL; \
109 return WINED3DERR_OUTOFVIDEOMEMORY; \
111 object->resource.allocatedMemory = (BYTE *)(((ULONG_PTR) object->resource.heapMemory + (RESOURCE_ALIGNMENT - 1)) & ~(RESOURCE_ALIGNMENT - 1)); \
112 *pp##type = (IWineD3D##type *) object; \
113 IWineD3DDeviceImpl_AddResource(iface, (IWineD3DResource *)object) ;\
114 TRACE("(%p) : Created resource %p\n", This, object); \
117 #define D3DINITIALIZEBASETEXTURE(_basetexture) { \
118 _basetexture.levels = Levels; \
119 _basetexture.filterType = (Usage & WINED3DUSAGE_AUTOGENMIPMAP) ? WINED3DTEXF_LINEAR : WINED3DTEXF_NONE; \
120 _basetexture.LOD = 0; \
121 _basetexture.dirty = TRUE; \
122 _basetexture.is_srgb = FALSE; \
123 _basetexture.srgb_mode_change_count = 0; \
126 /**********************************************************
127 * Global variable / Constants follow
128 **********************************************************/
129 const float identity[16] = {1,0,0,0, 0,1,0,0, 0,0,1,0, 0,0,0,1}; /* When needed for comparisons */
131 /**********************************************************
132 * IUnknown parts follows
133 **********************************************************/
135 static HRESULT WINAPI IWineD3DDeviceImpl_QueryInterface(IWineD3DDevice *iface,REFIID riid,LPVOID *ppobj)
137 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
139 TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
140 if (IsEqualGUID(riid, &IID_IUnknown)
141 || IsEqualGUID(riid, &IID_IWineD3DBase)
142 || IsEqualGUID(riid, &IID_IWineD3DDevice)) {
143 IUnknown_AddRef(iface);
144 *ppobj = This;
145 return S_OK;
147 *ppobj = NULL;
148 return E_NOINTERFACE;
151 static ULONG WINAPI IWineD3DDeviceImpl_AddRef(IWineD3DDevice *iface) {
152 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
153 ULONG refCount = InterlockedIncrement(&This->ref);
155 TRACE("(%p) : AddRef increasing from %d\n", This, refCount - 1);
156 return refCount;
159 static ULONG WINAPI IWineD3DDeviceImpl_Release(IWineD3DDevice *iface) {
160 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
161 ULONG refCount = InterlockedDecrement(&This->ref);
163 TRACE("(%p) : Releasing from %d\n", This, refCount + 1);
165 if (!refCount) {
166 /* TODO: Clean up all the surfaces and textures! */
167 /* NOTE: You must release the parent if the object was created via a callback
168 ** ***************************/
170 if (!list_empty(&This->resources)) {
171 FIXME("(%p) Device released with resources still bound, acceptable but unexpected\n", This);
172 dumpResources(&This->resources);
175 if(This->contexts) ERR("Context array not freed!\n");
176 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
177 This->haveHardwareCursor = FALSE;
179 IWineD3D_Release(This->wineD3D);
180 This->wineD3D = NULL;
181 HeapFree(GetProcessHeap(), 0, This);
182 TRACE("Freed device %p\n", This);
183 This = NULL;
185 return refCount;
188 /**********************************************************
189 * IWineD3DDevice implementation follows
190 **********************************************************/
191 static HRESULT WINAPI IWineD3DDeviceImpl_GetParent(IWineD3DDevice *iface, IUnknown **pParent) {
192 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
193 *pParent = This->parent;
194 IUnknown_AddRef(This->parent);
195 return WINED3D_OK;
198 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexBuffer(IWineD3DDevice *iface, UINT Size, DWORD Usage,
199 DWORD FVF, WINED3DPOOL Pool, IWineD3DVertexBuffer** ppVertexBuffer, HANDLE *sharedHandle,
200 IUnknown *parent) {
201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
202 IWineD3DVertexBufferImpl *object;
203 WINED3DFORMAT Format = WINED3DFMT_VERTEXDATA; /* Dummy format for now */
204 int dxVersion = ( (IWineD3DImpl *) This->wineD3D)->dxVersion;
205 BOOL conv;
207 if(Size == 0) {
208 WARN("Size 0 requested, returning WINED3DERR_INVALIDCALL\n");
209 *ppVertexBuffer = NULL;
210 return WINED3DERR_INVALIDCALL;
211 } else if(Pool == WINED3DPOOL_SCRATCH) {
212 /* The d3d9 testsuit shows that this is not allowed. It doesn't make much sense
213 * anyway, SCRATCH vertex buffers aren't usable anywhere
215 WARN("Vertex buffer in D3DPOOL_SCRATCH requested, returning WINED3DERR_INVALIDCALL\n");
216 *ppVertexBuffer = NULL;
217 return WINED3DERR_INVALIDCALL;
220 D3DCREATERESOURCEOBJECTINSTANCE(object, VertexBuffer, WINED3DRTYPE_VERTEXBUFFER, Size)
222 TRACE("(%p) : Size=%d, Usage=0x%08x, FVF=%x, Pool=%d - Memory@%p, Iface@%p\n", This, Size, Usage, FVF, Pool, object->resource.allocatedMemory, object);
223 *ppVertexBuffer = (IWineD3DVertexBuffer *)object;
225 object->fvf = FVF;
227 /* Observations show that drawStridedSlow is faster on dynamic VBs than converting +
228 * drawStridedFast (half-life 2).
230 * Basically converting the vertices in the buffer is quite expensive, and observations
231 * show that drawStridedSlow is faster than converting + uploading + drawStridedFast.
232 * Therefore do not create a VBO for WINED3DUSAGE_DYNAMIC buffers.
234 * Direct3D7 has another problem: Its vertexbuffer api doesn't offer a way to specify
235 * the range of vertices being locked, so each lock will require the whole buffer to be transformed.
236 * Moreover geometry data in dx7 is quite simple, so drawStridedSlow isn't a big hit. A plus
237 * is that the vertex buffers fvf can be trusted in dx7. So only create non-converted vbos for
238 * dx7 apps.
239 * There is a IDirect3DVertexBuffer7::Optimize call after which the buffer can't be locked any
240 * more. In this call we can convert dx7 buffers too.
242 conv = ((FVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) || (FVF & (WINED3DFVF_DIFFUSE | WINED3DFVF_SPECULAR));
243 if(!GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
244 TRACE("Not creating a vbo because GL_ARB_vertex_buffer is not supported\n");
245 } else if(Pool == WINED3DPOOL_SYSTEMMEM) {
246 TRACE("Not creating a vbo because the vertex buffer is in system memory\n");
247 } else if(Usage & WINED3DUSAGE_DYNAMIC) {
248 TRACE("Not creating a vbo because the buffer has dynamic usage\n");
249 } else if(dxVersion <= 7 && conv) {
250 TRACE("Not creating a vbo because dxVersion is 7 and the fvf needs conversion\n");
251 } else {
252 object->Flags |= VBFLAG_CREATEVBO;
254 return WINED3D_OK;
257 static void CreateIndexBufferVBO(IWineD3DDeviceImpl *This, IWineD3DIndexBufferImpl *object) {
258 GLenum error, glUsage;
259 TRACE("Creating VBO for Index Buffer %p\n", object);
261 /* The following code will modify the ELEMENT_ARRAY_BUFFER binding, make sure it is
262 * restored on the next draw
264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
266 /* Make sure that a context is there. Needed in a multithreaded environment. Otherwise this call is a nop */
267 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
268 ENTER_GL();
270 while(glGetError());
272 GL_EXTCALL(glGenBuffersARB(1, &object->vbo));
273 error = glGetError();
274 if(error != GL_NO_ERROR || object->vbo == 0) {
275 ERR("Creating a vbo failed with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
276 goto out;
279 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->vbo));
280 error = glGetError();
281 if(error != GL_NO_ERROR) {
282 ERR("Failed to bind index buffer with error %s (%#x), continuing without vbo for this buffer\n", debug_glerror(error), error);
283 goto out;
286 /* Use static write only usage for now. Dynamic index buffers stay in sysmem, and due to the sysmem
287 * copy no readback will be needed
289 glUsage = GL_STATIC_DRAW_ARB;
290 GL_EXTCALL(glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER_ARB, object->resource.size, NULL, glUsage));
291 error = glGetError();
292 if(error != GL_NO_ERROR) {
293 ERR("Failed to initialize the index buffer with error %s (%#x)\n", debug_glerror(error), error);
294 goto out;
296 LEAVE_GL();
297 TRACE("Successfully created vbo %d for index buffer %p\n", object->vbo, object);
298 return;
300 out:
301 GL_EXTCALL(glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER_ARB, 0));
302 GL_EXTCALL(glDeleteBuffersARB(1, &object->vbo));
303 LEAVE_GL();
304 object->vbo = 0;
307 static HRESULT WINAPI IWineD3DDeviceImpl_CreateIndexBuffer(IWineD3DDevice *iface, UINT Length, DWORD Usage,
308 WINED3DFORMAT Format, WINED3DPOOL Pool, IWineD3DIndexBuffer** ppIndexBuffer,
309 HANDLE *sharedHandle, IUnknown *parent) {
310 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
311 IWineD3DIndexBufferImpl *object;
312 TRACE("(%p) Creating index buffer\n", This);
314 /* Allocate the storage for the device */
315 D3DCREATERESOURCEOBJECTINSTANCE(object,IndexBuffer,WINED3DRTYPE_INDEXBUFFER, Length)
317 if(Pool != WINED3DPOOL_SYSTEMMEM && !(Usage & WINED3DUSAGE_DYNAMIC) && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
318 CreateIndexBufferVBO(This, object);
321 TRACE("(%p) : Len=%d, Use=%x, Format=(%u,%s), Pool=%d - Memory@%p, Iface@%p\n", This, Length, Usage, Format,
322 debug_d3dformat(Format), Pool, object, object->resource.allocatedMemory);
323 *ppIndexBuffer = (IWineD3DIndexBuffer *) object;
325 return WINED3D_OK;
328 static HRESULT WINAPI IWineD3DDeviceImpl_CreateStateBlock(IWineD3DDevice* iface, WINED3DSTATEBLOCKTYPE Type, IWineD3DStateBlock** ppStateBlock, IUnknown *parent) {
330 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
331 IWineD3DStateBlockImpl *object;
332 int i, j;
333 HRESULT temp_result;
335 D3DCREATEOBJECTINSTANCE(object, StateBlock)
336 object->blockType = Type;
338 for(i = 0; i < LIGHTMAP_SIZE; i++) {
339 list_init(&object->lightMap[i]);
342 /* Special case - Used during initialization to produce a placeholder stateblock
343 so other functions called can update a state block */
344 if (Type == WINED3DSBT_INIT) {
345 /* Don't bother increasing the reference count otherwise a device will never
346 be freed due to circular dependencies */
347 return WINED3D_OK;
350 temp_result = allocate_shader_constants(object);
351 if (WINED3D_OK != temp_result)
352 return temp_result;
354 /* Otherwise, might as well set the whole state block to the appropriate values */
355 if (This->stateBlock != NULL)
356 stateblock_copy((IWineD3DStateBlock*) object, (IWineD3DStateBlock*) This->stateBlock);
357 else
358 memset(object->streamFreq, 1, sizeof(object->streamFreq));
360 /* Reset the ref and type after kludging it */
361 object->wineD3DDevice = This;
362 object->ref = 1;
363 object->blockType = Type;
365 TRACE("Updating changed flags appropriate for type %d\n", Type);
367 if (Type == WINED3DSBT_ALL) {
369 TRACE("ALL => Pretend everything has changed\n");
370 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, TRUE);
372 /* Lights are not part of the changed / set structure */
373 for(j = 0; j < LIGHTMAP_SIZE; j++) {
374 struct list *e;
375 LIST_FOR_EACH(e, &object->lightMap[j]) {
376 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
377 light->changed = TRUE;
378 light->enabledChanged = TRUE;
381 for(j = 1; j <= WINEHIGHEST_RENDER_STATE; j++) {
382 object->contained_render_states[j - 1] = j;
384 object->num_contained_render_states = WINEHIGHEST_RENDER_STATE;
385 /* TODO: Filter unused transforms between TEXTURE8 and WORLD0? */
386 for(j = 1; j <= HIGHEST_TRANSFORMSTATE; j++) {
387 object->contained_transform_states[j - 1] = j;
389 object->num_contained_transform_states = HIGHEST_TRANSFORMSTATE;
390 for(j = 0; j < GL_LIMITS(vshader_constantsF); j++) {
391 object->contained_vs_consts_f[j] = j;
393 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
394 for(j = 0; j < MAX_CONST_I; j++) {
395 object->contained_vs_consts_i[j] = j;
397 object->num_contained_vs_consts_i = MAX_CONST_I;
398 for(j = 0; j < MAX_CONST_B; j++) {
399 object->contained_vs_consts_b[j] = j;
401 object->num_contained_vs_consts_b = MAX_CONST_B;
402 for(j = 0; j < GL_LIMITS(pshader_constantsF); j++) {
403 object->contained_ps_consts_f[j] = j;
405 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
406 for(j = 0; j < MAX_CONST_I; j++) {
407 object->contained_ps_consts_i[j] = j;
409 object->num_contained_ps_consts_i = MAX_CONST_I;
410 for(j = 0; j < MAX_CONST_B; j++) {
411 object->contained_ps_consts_b[j] = j;
413 object->num_contained_ps_consts_b = MAX_CONST_B;
414 for(i = 0; i < MAX_TEXTURES; i++) {
415 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
416 object->contained_tss_states[object->num_contained_tss_states].stage = i;
417 object->contained_tss_states[object->num_contained_tss_states].state = j;
418 object->num_contained_tss_states++;
421 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
422 for(j = 1; j <= WINED3D_HIGHEST_SAMPLER_STATE; j++) {
423 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
424 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
425 object->num_contained_sampler_states++;
429 for(i = 0; i < MAX_STREAMS; i++) {
430 if(object->streamSource[i]) {
431 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
434 if(object->pIndexData) {
435 IWineD3DIndexBuffer_AddRef(object->pIndexData);
437 if(object->vertexShader) {
438 IWineD3DVertexShader_AddRef(object->vertexShader);
440 if(object->pixelShader) {
441 IWineD3DPixelShader_AddRef(object->pixelShader);
444 } else if (Type == WINED3DSBT_PIXELSTATE) {
446 TRACE("PIXELSTATE => Pretend all pixel shates have changed\n");
447 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
449 object->changed.pixelShader = TRUE;
451 /* Pixel Shader Constants */
452 for (i = 0; i < GL_LIMITS(pshader_constantsF); ++i) {
453 object->contained_ps_consts_f[i] = i;
454 object->changed.pixelShaderConstantsF[i] = TRUE;
456 object->num_contained_ps_consts_f = GL_LIMITS(pshader_constantsF);
457 for (i = 0; i < MAX_CONST_B; ++i) {
458 object->contained_ps_consts_b[i] = i;
459 object->changed.pixelShaderConstantsB[i] = TRUE;
461 object->num_contained_ps_consts_b = MAX_CONST_B;
462 for (i = 0; i < MAX_CONST_I; ++i) {
463 object->contained_ps_consts_i[i] = i;
464 object->changed.pixelShaderConstantsI[i] = TRUE;
466 object->num_contained_ps_consts_i = MAX_CONST_I;
468 for (i = 0; i < NUM_SAVEDPIXELSTATES_R; i++) {
469 object->changed.renderState[SavedPixelStates_R[i]] = TRUE;
470 object->contained_render_states[i] = SavedPixelStates_R[i];
472 object->num_contained_render_states = NUM_SAVEDPIXELSTATES_R;
473 for (j = 0; j < MAX_TEXTURES; j++) {
474 for (i = 0; i < NUM_SAVEDPIXELSTATES_T; i++) {
475 object->changed.textureState[j][SavedPixelStates_T[i]] = TRUE;
476 object->contained_tss_states[object->num_contained_tss_states].stage = j;
477 object->contained_tss_states[object->num_contained_tss_states].state = SavedPixelStates_T[i];
478 object->num_contained_tss_states++;
481 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++) {
482 for (i =0; i < NUM_SAVEDPIXELSTATES_S;i++) {
483 object->changed.samplerState[j][SavedPixelStates_S[i]] = TRUE;
484 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
485 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedPixelStates_S[i];
486 object->num_contained_sampler_states++;
489 if(object->pixelShader) {
490 IWineD3DPixelShader_AddRef(object->pixelShader);
493 /* Pixel state blocks do not contain vertex buffers. Set them to NULL to avoid wrong refcounting
494 * on them. This makes releasing the buffer easier
496 for(i = 0; i < MAX_STREAMS; i++) {
497 object->streamSource[i] = NULL;
499 object->pIndexData = NULL;
500 object->vertexShader = NULL;
502 } else if (Type == WINED3DSBT_VERTEXSTATE) {
504 TRACE("VERTEXSTATE => Pretend all vertex shates have changed\n");
505 stateblock_savedstates_set((IWineD3DStateBlock*) object, &object->changed, FALSE);
507 object->changed.vertexShader = TRUE;
509 /* Vertex Shader Constants */
510 for (i = 0; i < GL_LIMITS(vshader_constantsF); ++i) {
511 object->changed.vertexShaderConstantsF[i] = TRUE;
512 object->contained_vs_consts_f[i] = i;
514 object->num_contained_vs_consts_f = GL_LIMITS(vshader_constantsF);
515 for (i = 0; i < MAX_CONST_B; ++i) {
516 object->changed.vertexShaderConstantsB[i] = TRUE;
517 object->contained_vs_consts_b[i] = i;
519 object->num_contained_vs_consts_b = MAX_CONST_B;
520 for (i = 0; i < MAX_CONST_I; ++i) {
521 object->changed.vertexShaderConstantsI[i] = TRUE;
522 object->contained_vs_consts_i[i] = i;
524 object->num_contained_vs_consts_i = MAX_CONST_I;
525 for (i = 0; i < NUM_SAVEDVERTEXSTATES_R; i++) {
526 object->changed.renderState[SavedVertexStates_R[i]] = TRUE;
527 object->contained_render_states[i] = SavedVertexStates_R[i];
529 object->num_contained_render_states = NUM_SAVEDVERTEXSTATES_R;
530 for (j = 0; j < MAX_TEXTURES; j++) {
531 for (i = 0; i < NUM_SAVEDVERTEXSTATES_T; i++) {
532 object->changed.textureState[j][SavedVertexStates_T[i]] = TRUE;
533 object->contained_tss_states[object->num_contained_tss_states].stage = j;
534 object->contained_tss_states[object->num_contained_tss_states].state = SavedVertexStates_T[i];
535 object->num_contained_tss_states++;
538 for (j = 0 ; j < MAX_COMBINED_SAMPLERS; j++){
539 for (i =0; i < NUM_SAVEDVERTEXSTATES_S;i++) {
540 object->changed.samplerState[j][SavedVertexStates_S[i]] = TRUE;
541 object->contained_sampler_states[object->num_contained_sampler_states].stage = j;
542 object->contained_sampler_states[object->num_contained_sampler_states].state = SavedVertexStates_S[i];
543 object->num_contained_sampler_states++;
547 for(j = 0; j < LIGHTMAP_SIZE; j++) {
548 struct list *e;
549 LIST_FOR_EACH(e, &object->lightMap[j]) {
550 PLIGHTINFOEL *light = LIST_ENTRY(e, PLIGHTINFOEL, entry);
551 light->changed = TRUE;
552 light->enabledChanged = TRUE;
556 for(i = 0; i < MAX_STREAMS; i++) {
557 if(object->streamSource[i]) {
558 IWineD3DVertexBuffer_AddRef(object->streamSource[i]);
561 if(object->vertexShader) {
562 IWineD3DVertexShader_AddRef(object->vertexShader);
564 object->pIndexData = NULL;
565 object->pixelShader = NULL;
566 } else {
567 FIXME("Unrecognized state block type %d\n", Type);
570 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, object);
571 return WINED3D_OK;
574 /* ************************************
575 MSDN:
576 [in] Render targets are not lockable unless the application specifies TRUE for Lockable. Note that lockable render targets reduce performance on some graphics hardware.
578 Discard
579 [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
581 If this flag is set, the contents of the depth stencil buffer will be invalid after calling either IDirect3DDevice9::Present or IDirect3DDevice9::SetDepthStencilSurface with a different depth surface.
583 ******************************** */
585 static HRESULT WINAPI IWineD3DDeviceImpl_CreateSurface(IWineD3DDevice *iface, UINT Width, UINT Height, WINED3DFORMAT Format, BOOL Lockable, BOOL Discard, UINT Level, IWineD3DSurface **ppSurface,WINED3DRESOURCETYPE Type, DWORD Usage, WINED3DPOOL Pool, WINED3DMULTISAMPLE_TYPE MultiSample ,DWORD MultisampleQuality, HANDLE* pSharedHandle, WINED3DSURFTYPE Impl, IUnknown *parent) {
586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
587 IWineD3DSurfaceImpl *object; /*NOTE: impl ref allowed since this is a create function */
588 unsigned int Size = 1;
589 const GlPixelFormatDesc *glDesc;
590 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
591 UINT mul_4w, mul_4h;
592 TRACE("(%p) Create surface\n",This);
594 /** FIXME: Check ranges on the inputs are valid
595 * MSDN
596 * MultisampleQuality
597 * [in] Quality level. The valid range is between zero and one less than the level
598 * returned by pQualityLevels used by IDirect3D9::CheckDeviceMultiSampleType.
599 * Passing a larger value returns the error WINED3DERR_INVALIDCALL. The MultisampleQuality
600 * values of paired render targets, depth stencil surfaces, and the MultiSample type
601 * must all match.
602 *******************************/
606 * TODO: Discard MSDN
607 * [in] Set this flag to TRUE to enable z-buffer discarding, and FALSE otherwise.
609 * If this flag is set, the contents of the depth stencil buffer will be
610 * invalid after calling either IDirect3DDevice9::Present or * IDirect3DDevice9::SetDepthStencilSurface
611 * with a different depth surface.
613 *This flag has the same behavior as the constant, D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL, in D3DPRESENTFLAG.
614 ***************************/
616 if(MultisampleQuality > 0) {
617 FIXME("MultisampleQuality set to %d, substituting 0\n", MultisampleQuality);
618 MultisampleQuality=0;
621 /** FIXME: Check that the format is supported
622 * by the device.
623 *******************************/
625 /** DXTn mipmaps use the same number of 'levels' down to eg. 8x1, but since
626 * it is based around 4x4 pixel blocks it requires padding, so allocate enough
627 * space!
628 *********************************/
629 mul_4w = (Width + 3) & ~3;
630 mul_4h = (Height + 3) & ~3;
631 if (WINED3DFMT_UNKNOWN == Format) {
632 Size = 0;
633 } else if (Format == WINED3DFMT_DXT1) {
634 /* DXT1 is half byte per pixel */
635 Size = (mul_4w * tableEntry->bpp * mul_4h) >> 1;
637 } else if (Format == WINED3DFMT_DXT2 || Format == WINED3DFMT_DXT3 ||
638 Format == WINED3DFMT_DXT4 || Format == WINED3DFMT_DXT5 ||
639 Format == WINED3DFMT_ATI2N) {
640 Size = (mul_4w * tableEntry->bpp * mul_4h);
641 } else {
642 /* The pitch is a multiple of 4 bytes */
643 Size = ((Width * tableEntry->bpp) + This->surface_alignment - 1) & ~(This->surface_alignment - 1);
644 Size *= Height;
647 if(glDesc->heightscale != 0.0) Size *= glDesc->heightscale;
649 /** Create and initialise the surface resource **/
650 D3DCREATERESOURCEOBJECTINSTANCE(object,Surface,WINED3DRTYPE_SURFACE, Size)
651 /* "Standalone" surface */
652 IWineD3DSurface_SetContainer((IWineD3DSurface *)object, NULL);
654 object->currentDesc.Width = Width;
655 object->currentDesc.Height = Height;
656 object->currentDesc.MultiSampleType = MultiSample;
657 object->currentDesc.MultiSampleQuality = MultisampleQuality;
658 object->glDescription.level = Level;
659 object->heightscale = glDesc->heightscale != 0.0 ? glDesc->heightscale : 1.0;
660 list_init(&object->overlays);
662 /* Flags */
663 object->Flags = SFLAG_NORMCOORD; /* Default to normalized coords */
664 object->Flags |= Discard ? SFLAG_DISCARD : 0;
665 object->Flags |= (WINED3DFMT_D16_LOCKABLE == Format) ? SFLAG_LOCKABLE : 0;
666 object->Flags |= Lockable ? SFLAG_LOCKABLE : 0;
669 if (WINED3DFMT_UNKNOWN != Format) {
670 object->bytesPerPixel = tableEntry->bpp;
671 } else {
672 object->bytesPerPixel = 0;
675 /** TODO: change this into a texture transform matrix so that it's processed in hardware **/
677 TRACE("Pool %d %d %d %d\n",Pool, WINED3DPOOL_DEFAULT, WINED3DPOOL_MANAGED, WINED3DPOOL_SYSTEMMEM);
679 /** Quick lockable sanity check TODO: remove this after surfaces, usage and lockability have been debugged properly
680 * this function is too deep to need to care about things like this.
681 * Levels need to be checked too, and possibly Type since they all affect what can be done.
682 * ****************************************/
683 switch(Pool) {
684 case WINED3DPOOL_SCRATCH:
685 if(!Lockable)
686 FIXME("Create surface called with a pool of SCRATCH and a Lockable of FALSE "
687 "which are mutually exclusive, setting lockable to TRUE\n");
688 Lockable = TRUE;
689 break;
690 case WINED3DPOOL_SYSTEMMEM:
691 if(!Lockable) FIXME("Create surface called with a pool of SYSTEMMEM and a Lockable of FALSE, "
692 "this is acceptable but unexpected (I can't know how the surface can be usable!)\n");
693 case WINED3DPOOL_MANAGED:
694 if(Usage == WINED3DUSAGE_DYNAMIC) FIXME("Create surface called with a pool of MANAGED and a "
695 "Usage of DYNAMIC which are mutually exclusive, not doing "
696 "anything just telling you.\n");
697 break;
698 case WINED3DPOOL_DEFAULT: /*TODO: Create offscreen plain can cause this check to fail..., find out if it should */
699 if(!(Usage & WINED3DUSAGE_DYNAMIC) && !(Usage & WINED3DUSAGE_RENDERTARGET)
700 && !(Usage && WINED3DUSAGE_DEPTHSTENCIL ) && Lockable)
701 WARN("Creating a surface with a POOL of DEFAULT with Lockable true, that doesn't specify DYNAMIC usage.\n");
702 break;
703 default:
704 FIXME("(%p) Unknown pool %d\n", This, Pool);
705 break;
708 if (Usage & WINED3DUSAGE_RENDERTARGET && Pool != WINED3DPOOL_DEFAULT) {
709 FIXME("Trying to create a render target that isn't in the default pool\n");
712 /* mark the texture as dirty so that it gets loaded first time around*/
713 IWineD3DSurface_AddDirtyRect(*ppSurface, NULL);
714 TRACE("(%p) : w(%d) h(%d) fmt(%d,%s) lockable(%d) surf@%p, surfmem@%p, %d bytes\n",
715 This, Width, Height, Format, debug_d3dformat(Format),
716 (WINED3DFMT_D16_LOCKABLE == Format), *ppSurface, object->resource.allocatedMemory, object->resource.size);
718 /* Look at the implementation and set the correct Vtable */
719 switch(Impl) {
720 case SURFACE_OPENGL:
721 /* Check if a 3D adapter is available when creating gl surfaces */
722 if(!This->adapter) {
723 ERR("OpenGL surfaces are not available without opengl\n");
724 HeapFree(GetProcessHeap(), 0, object->resource.allocatedMemory);
725 HeapFree(GetProcessHeap(), 0, object);
726 return WINED3DERR_NOTAVAILABLE;
728 break;
730 case SURFACE_GDI:
731 object->lpVtbl = &IWineGDISurface_Vtbl;
732 break;
734 default:
735 /* To be sure to catch this */
736 ERR("Unknown requested surface implementation %d!\n", Impl);
737 IWineD3DSurface_Release((IWineD3DSurface *) object);
738 return WINED3DERR_INVALIDCALL;
741 list_init(&object->renderbuffers);
743 /* Call the private setup routine */
744 return IWineD3DSurface_PrivateSetup( (IWineD3DSurface *) object );
748 static HRESULT WINAPI IWineD3DDeviceImpl_CreateTexture(IWineD3DDevice *iface, UINT Width, UINT Height, UINT Levels,
749 DWORD Usage, WINED3DFORMAT Format, WINED3DPOOL Pool,
750 IWineD3DTexture** ppTexture, HANDLE* pSharedHandle, IUnknown *parent,
751 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
754 IWineD3DTextureImpl *object;
755 unsigned int i;
756 UINT tmpW;
757 UINT tmpH;
758 HRESULT hr;
759 unsigned int pow2Width;
760 unsigned int pow2Height;
761 const GlPixelFormatDesc *glDesc;
762 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
764 TRACE("(%p) : Width %d, Height %d, Levels %d, Usage %#x\n", This, Width, Height, Levels, Usage);
765 TRACE("Format %#x (%s), Pool %#x, ppTexture %p, pSharedHandle %p, parent %p\n",
766 Format, debug_d3dformat(Format), Pool, ppTexture, pSharedHandle, parent);
768 /* TODO: It should only be possible to create textures for formats
769 that are reported as supported */
770 if (WINED3DFMT_UNKNOWN >= Format) {
771 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
772 return WINED3DERR_INVALIDCALL;
775 D3DCREATERESOURCEOBJECTINSTANCE(object, Texture, WINED3DRTYPE_TEXTURE, 0);
776 D3DINITIALIZEBASETEXTURE(object->baseTexture);
777 object->width = Width;
778 object->height = Height;
780 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
781 object->baseTexture.minMipLookup = &minMipLookup;
782 object->baseTexture.magLookup = &magLookup;
783 } else {
784 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
785 object->baseTexture.magLookup = &magLookup_noFilter;
788 /** Non-power2 support **/
789 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO)) {
790 pow2Width = Width;
791 pow2Height = Height;
792 } else {
793 /* Find the nearest pow2 match */
794 pow2Width = pow2Height = 1;
795 while (pow2Width < Width) pow2Width <<= 1;
796 while (pow2Height < Height) pow2Height <<= 1;
798 if(pow2Width != Width || pow2Height != Height) {
799 if(Levels > 1) {
800 WARN("Attempted to create a mipmapped np2 texture without unconditional np2 support\n");
801 HeapFree(GetProcessHeap(), 0, object);
802 *ppTexture = NULL;
803 return WINED3DERR_INVALIDCALL;
804 } else {
805 Levels = 1;
810 /** FIXME: add support for real non-power-two if it's provided by the video card **/
811 /* Precalculated scaling for 'faked' non power of two texture coords.
812 Second also don't use ARB_TEXTURE_RECTANGLE in case the surface format is P8 and EXT_PALETTED_TEXTURE
813 is used in combination with texture uploads (RTL_READTEX/RTL_TEXTEX). The reason is that EXT_PALETTED_TEXTURE
814 doesn't work in combination with ARB_TEXTURE_RECTANGLE.
816 if(GL_SUPPORT(WINE_NORMALIZED_TEXRECT) && (Width != pow2Width || Height != pow2Height)) {
817 object->baseTexture.pow2Matrix[0] = 1.0;
818 object->baseTexture.pow2Matrix[5] = 1.0;
819 object->baseTexture.pow2Matrix[10] = 1.0;
820 object->baseTexture.pow2Matrix[15] = 1.0;
821 object->target = GL_TEXTURE_2D;
822 object->cond_np2 = TRUE;
823 pow2Width = Width;
824 pow2Height = Height;
825 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
826 } else if(GL_SUPPORT(ARB_TEXTURE_RECTANGLE) &&
827 (Width != pow2Width || Height != pow2Height) &&
828 !((Format == WINED3DFMT_P8) && GL_SUPPORT(EXT_PALETTED_TEXTURE) && (wined3d_settings.rendertargetlock_mode == RTL_READTEX || wined3d_settings.rendertargetlock_mode == RTL_TEXTEX)))
830 object->baseTexture.pow2Matrix[0] = (float)Width;
831 object->baseTexture.pow2Matrix[5] = (float)Height;
832 object->baseTexture.pow2Matrix[10] = 1.0;
833 object->baseTexture.pow2Matrix[15] = 1.0;
834 object->target = GL_TEXTURE_RECTANGLE_ARB;
835 object->cond_np2 = TRUE;
836 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
837 } else {
838 object->baseTexture.pow2Matrix[0] = (((float)Width) / ((float)pow2Width));
839 object->baseTexture.pow2Matrix[5] = (((float)Height) / ((float)pow2Height));
840 object->baseTexture.pow2Matrix[10] = 1.0;
841 object->baseTexture.pow2Matrix[15] = 1.0;
842 object->target = GL_TEXTURE_2D;
843 object->cond_np2 = FALSE;
845 TRACE(" xf(%f) yf(%f)\n", object->baseTexture.pow2Matrix[0], object->baseTexture.pow2Matrix[5]);
847 /* Calculate levels for mip mapping */
848 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
849 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
850 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
851 return WINED3DERR_INVALIDCALL;
853 if(Levels > 1) {
854 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
855 return WINED3DERR_INVALIDCALL;
857 object->baseTexture.levels = 1;
858 } else if (Levels == 0) {
859 TRACE("calculating levels %d\n", object->baseTexture.levels);
860 object->baseTexture.levels++;
861 tmpW = Width;
862 tmpH = Height;
863 while (tmpW > 1 || tmpH > 1) {
864 tmpW = max(1, tmpW >> 1);
865 tmpH = max(1, tmpH >> 1);
866 object->baseTexture.levels++;
868 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
871 /* Generate all the surfaces */
872 tmpW = Width;
873 tmpH = Height;
874 for (i = 0; i < object->baseTexture.levels; i++)
876 /* use the callback to create the texture surface */
877 hr = D3DCB_CreateSurface(This->parent, parent, tmpW, tmpH, Format, Usage, Pool, i, WINED3DCUBEMAP_FACE_POSITIVE_X, &object->surfaces[i],NULL);
878 if (hr!= WINED3D_OK || ( (IWineD3DSurfaceImpl *) object->surfaces[i])->Flags & SFLAG_OVERSIZE) {
879 FIXME("Failed to create surface %p\n", object);
880 /* clean up */
881 object->surfaces[i] = NULL;
882 IWineD3DTexture_Release((IWineD3DTexture *)object);
884 *ppTexture = NULL;
885 return hr;
888 IWineD3DSurface_SetContainer(object->surfaces[i], (IWineD3DBase *)object);
889 TRACE("Created surface level %d @ %p\n", i, object->surfaces[i]);
890 /* calculate the next mipmap level */
891 tmpW = max(1, tmpW >> 1);
892 tmpH = max(1, tmpH >> 1);
894 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
896 TRACE("(%p) : Created texture %p\n", This, object);
897 return WINED3D_OK;
900 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolumeTexture(IWineD3DDevice *iface,
901 UINT Width, UINT Height, UINT Depth,
902 UINT Levels, DWORD Usage,
903 WINED3DFORMAT Format, WINED3DPOOL Pool,
904 IWineD3DVolumeTexture **ppVolumeTexture,
905 HANDLE *pSharedHandle, IUnknown *parent,
906 D3DCB_CREATEVOLUMEFN D3DCB_CreateVolume) {
908 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
909 IWineD3DVolumeTextureImpl *object;
910 unsigned int i;
911 UINT tmpW;
912 UINT tmpH;
913 UINT tmpD;
914 const GlPixelFormatDesc *glDesc;
916 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
918 /* TODO: It should only be possible to create textures for formats
919 that are reported as supported */
920 if (WINED3DFMT_UNKNOWN >= Format) {
921 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
922 return WINED3DERR_INVALIDCALL;
924 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
925 WARN("(%p) : Texture cannot be created - no volume texture support\n", This);
926 return WINED3DERR_INVALIDCALL;
929 D3DCREATERESOURCEOBJECTINSTANCE(object, VolumeTexture, WINED3DRTYPE_VOLUMETEXTURE, 0);
930 D3DINITIALIZEBASETEXTURE(object->baseTexture);
932 TRACE("(%p) : W(%d) H(%d) D(%d), Lvl(%d) Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
933 Depth, Levels, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
935 object->width = Width;
936 object->height = Height;
937 object->depth = Depth;
939 /* Is NP2 support for volumes needed? */
940 object->baseTexture.pow2Matrix[ 0] = 1.0;
941 object->baseTexture.pow2Matrix[ 5] = 1.0;
942 object->baseTexture.pow2Matrix[10] = 1.0;
943 object->baseTexture.pow2Matrix[15] = 1.0;
945 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
946 object->baseTexture.minMipLookup = &minMipLookup;
947 object->baseTexture.magLookup = &magLookup;
948 } else {
949 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
950 object->baseTexture.magLookup = &magLookup_noFilter;
953 /* Calculate levels for mip mapping */
954 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
955 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
956 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
957 return WINED3DERR_INVALIDCALL;
959 if(Levels > 1) {
960 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
961 return WINED3DERR_INVALIDCALL;
963 Levels = 1;
964 } else if (Levels == 0) {
965 object->baseTexture.levels++;
966 tmpW = Width;
967 tmpH = Height;
968 tmpD = Depth;
969 while (tmpW > 1 || tmpH > 1 || tmpD > 1) {
970 tmpW = max(1, tmpW >> 1);
971 tmpH = max(1, tmpH >> 1);
972 tmpD = max(1, tmpD >> 1);
973 object->baseTexture.levels++;
975 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
978 /* Generate all the surfaces */
979 tmpW = Width;
980 tmpH = Height;
981 tmpD = Depth;
983 for (i = 0; i < object->baseTexture.levels; i++)
985 HRESULT hr;
986 /* Create the volume */
987 hr = D3DCB_CreateVolume(This->parent, parent, tmpW, tmpH, tmpD, Format, Pool, Usage,
988 &object->volumes[i], pSharedHandle);
990 if(FAILED(hr)) {
991 ERR("Creating a volume for the volume texture failed(%08x)\n", hr);
992 IWineD3DVolumeTexture_Release((IWineD3DVolumeTexture *) object);
993 *ppVolumeTexture = NULL;
994 return hr;
997 /* Set its container to this object */
998 IWineD3DVolume_SetContainer(object->volumes[i], (IWineD3DBase *)object);
1000 /* calculate the next mipmap level */
1001 tmpW = max(1, tmpW >> 1);
1002 tmpH = max(1, tmpH >> 1);
1003 tmpD = max(1, tmpD >> 1);
1005 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1007 *ppVolumeTexture = (IWineD3DVolumeTexture *) object;
1008 TRACE("(%p) : Created volume texture %p\n", This, object);
1009 return WINED3D_OK;
1012 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVolume(IWineD3DDevice *iface,
1013 UINT Width, UINT Height, UINT Depth,
1014 DWORD Usage,
1015 WINED3DFORMAT Format, WINED3DPOOL Pool,
1016 IWineD3DVolume** ppVolume,
1017 HANDLE* pSharedHandle, IUnknown *parent) {
1019 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1020 IWineD3DVolumeImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1021 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(Format, NULL, NULL);
1023 if(!GL_SUPPORT(EXT_TEXTURE3D)) {
1024 WARN("(%p) : Volume cannot be created - no volume texture support\n", This);
1025 return WINED3DERR_INVALIDCALL;
1028 D3DCREATERESOURCEOBJECTINSTANCE(object, Volume, WINED3DRTYPE_VOLUME, ((Width * formatDesc->bpp) * Height * Depth))
1030 TRACE("(%p) : W(%d) H(%d) D(%d), Usage(%d), Fmt(%u,%s), Pool(%s)\n", This, Width, Height,
1031 Depth, Usage, Format, debug_d3dformat(Format), debug_d3dpool(Pool));
1033 object->currentDesc.Width = Width;
1034 object->currentDesc.Height = Height;
1035 object->currentDesc.Depth = Depth;
1036 object->bytesPerPixel = formatDesc->bpp;
1038 /** Note: Volume textures cannot be dxtn, hence no need to check here **/
1039 object->lockable = TRUE;
1040 object->locked = FALSE;
1041 memset(&object->lockedBox, 0, sizeof(WINED3DBOX));
1042 object->dirty = TRUE;
1044 return IWineD3DVolume_AddDirtyBox((IWineD3DVolume *) object, NULL);
1047 static HRESULT WINAPI IWineD3DDeviceImpl_CreateCubeTexture(IWineD3DDevice *iface, UINT EdgeLength,
1048 UINT Levels, DWORD Usage,
1049 WINED3DFORMAT Format, WINED3DPOOL Pool,
1050 IWineD3DCubeTexture **ppCubeTexture,
1051 HANDLE *pSharedHandle, IUnknown *parent,
1052 D3DCB_CREATESURFACEFN D3DCB_CreateSurface) {
1054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1055 IWineD3DCubeTextureImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1056 unsigned int i, j;
1057 UINT tmpW;
1058 HRESULT hr;
1059 unsigned int pow2EdgeLength = EdgeLength;
1060 const GlPixelFormatDesc *glDesc;
1061 getFormatDescEntry(Format, &GLINFO_LOCATION, &glDesc);
1063 /* TODO: It should only be possible to create textures for formats
1064 that are reported as supported */
1065 if (WINED3DFMT_UNKNOWN >= Format) {
1066 WARN("(%p) : Texture cannot be created with a format of WINED3DFMT_UNKNOWN\n", This);
1067 return WINED3DERR_INVALIDCALL;
1070 if (!GL_SUPPORT(ARB_TEXTURE_CUBE_MAP) && Pool != WINED3DPOOL_SCRATCH) {
1071 WARN("(%p) : Tried to create not supported cube texture\n", This);
1072 return WINED3DERR_INVALIDCALL;
1075 D3DCREATERESOURCEOBJECTINSTANCE(object, CubeTexture, WINED3DRTYPE_CUBETEXTURE, 0);
1076 D3DINITIALIZEBASETEXTURE(object->baseTexture);
1078 TRACE("(%p) Create Cube Texture\n", This);
1080 /** Non-power2 support **/
1082 /* Find the nearest pow2 match */
1083 pow2EdgeLength = 1;
1084 while (pow2EdgeLength < EdgeLength) pow2EdgeLength <<= 1;
1086 object->edgeLength = EdgeLength;
1087 /* TODO: support for native non-power 2 */
1088 /* Precalculated scaling for 'faked' non power of two texture coords */
1089 object->baseTexture.pow2Matrix[ 0] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1090 object->baseTexture.pow2Matrix[ 5] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1091 object->baseTexture.pow2Matrix[10] = ((float)EdgeLength) / ((float)pow2EdgeLength);
1092 object->baseTexture.pow2Matrix[15] = 1.0;
1094 if(glDesc->Flags & WINED3DFMT_FLAG_FILTERING) {
1095 object->baseTexture.minMipLookup = &minMipLookup;
1096 object->baseTexture.magLookup = &magLookup;
1097 } else {
1098 object->baseTexture.minMipLookup = &minMipLookup_noFilter;
1099 object->baseTexture.magLookup = &magLookup_noFilter;
1102 /* Calculate levels for mip mapping */
1103 if (Usage & WINED3DUSAGE_AUTOGENMIPMAP) {
1104 if(!GL_SUPPORT(SGIS_GENERATE_MIPMAP)) {
1105 WARN("No mipmap generation support, returning D3DERR_INVALIDCALL\n");
1106 HeapFree(GetProcessHeap(), 0, object);
1107 *ppCubeTexture = NULL;
1109 return WINED3DERR_INVALIDCALL;
1111 if(Levels > 1) {
1112 WARN("D3DUSAGE_AUTOGENMIPMAP is set, and level count > 1, returning D3DERR_INVALIDCALL\n");
1113 HeapFree(GetProcessHeap(), 0, object);
1114 *ppCubeTexture = NULL;
1116 return WINED3DERR_INVALIDCALL;
1118 Levels = 1;
1119 } else if (Levels == 0) {
1120 object->baseTexture.levels++;
1121 tmpW = EdgeLength;
1122 while (tmpW > 1) {
1123 tmpW = max(1, tmpW >> 1);
1124 object->baseTexture.levels++;
1126 TRACE("Calculated levels = %d\n", object->baseTexture.levels);
1129 /* Generate all the surfaces */
1130 tmpW = EdgeLength;
1131 for (i = 0; i < object->baseTexture.levels; i++) {
1133 /* Create the 6 faces */
1134 for (j = 0; j < 6; j++) {
1136 hr=D3DCB_CreateSurface(This->parent, parent, tmpW, tmpW, Format, Usage, Pool,
1137 i /* Level */, j, &object->surfaces[j][i],pSharedHandle);
1139 if(hr!= WINED3D_OK) {
1140 /* clean up */
1141 int k;
1142 int l;
1143 for (l = 0; l < j; l++) {
1144 IWineD3DSurface_Release(object->surfaces[l][i]);
1146 for (k = 0; k < i; k++) {
1147 for (l = 0; l < 6; l++) {
1148 IWineD3DSurface_Release(object->surfaces[l][k]);
1152 FIXME("(%p) Failed to create surface\n",object);
1153 HeapFree(GetProcessHeap(),0,object);
1154 *ppCubeTexture = NULL;
1155 return hr;
1157 IWineD3DSurface_SetContainer(object->surfaces[j][i], (IWineD3DBase *)object);
1158 TRACE("Created surface level %d @ %p,\n", i, object->surfaces[j][i]);
1160 tmpW = max(1, tmpW >> 1);
1162 object->baseTexture.shader_conversion_group = glDesc->conversion_group;
1164 TRACE("(%p) : Created Cube Texture %p\n", This, object);
1165 *ppCubeTexture = (IWineD3DCubeTexture *) object;
1166 return WINED3D_OK;
1169 static HRESULT WINAPI IWineD3DDeviceImpl_CreateQuery(IWineD3DDevice *iface, WINED3DQUERYTYPE Type, IWineD3DQuery **ppQuery, IUnknown* parent) {
1170 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1171 IWineD3DQueryImpl *object; /*NOTE: impl ref allowed since this is a create function */
1172 HRESULT hr = WINED3DERR_NOTAVAILABLE;
1173 const IWineD3DQueryVtbl *vtable;
1175 /* Just a check to see if we support this type of query */
1176 switch(Type) {
1177 case WINED3DQUERYTYPE_OCCLUSION:
1178 TRACE("(%p) occlusion query\n", This);
1179 if (GL_SUPPORT(ARB_OCCLUSION_QUERY))
1180 hr = WINED3D_OK;
1181 else
1182 WARN("Unsupported in local OpenGL implementation: ARB_OCCLUSION_QUERY/NV_OCCLUSION_QUERY\n");
1184 vtable = &IWineD3DOcclusionQuery_Vtbl;
1185 break;
1187 case WINED3DQUERYTYPE_EVENT:
1188 if(!(GL_SUPPORT(NV_FENCE) || GL_SUPPORT(APPLE_FENCE) )) {
1189 /* Half-Life 2 needs this query. It does not render the main menu correctly otherwise
1190 * Pretend to support it, faking this query does not do much harm except potentially lowering performance
1192 FIXME("(%p) Event query: Unimplemented, but pretending to be supported\n", This);
1194 vtable = &IWineD3DEventQuery_Vtbl;
1195 hr = WINED3D_OK;
1196 break;
1198 case WINED3DQUERYTYPE_VCACHE:
1199 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1200 case WINED3DQUERYTYPE_VERTEXSTATS:
1201 case WINED3DQUERYTYPE_TIMESTAMP:
1202 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1203 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1204 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1205 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1206 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1207 case WINED3DQUERYTYPE_PIXELTIMINGS:
1208 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1209 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1210 default:
1211 /* Use the base Query vtable until we have a special one for each query */
1212 vtable = &IWineD3DQuery_Vtbl;
1213 FIXME("(%p) Unhandled query type %d\n", This, Type);
1215 if(NULL == ppQuery || hr != WINED3D_OK) {
1216 return hr;
1219 D3DCREATEOBJECTINSTANCE(object, Query)
1220 object->lpVtbl = vtable;
1221 object->type = Type;
1222 object->state = QUERY_CREATED;
1223 /* allocated the 'extended' data based on the type of query requested */
1224 switch(Type){
1225 case WINED3DQUERYTYPE_OCCLUSION:
1226 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryOcclusionData));
1227 ((WineQueryOcclusionData *)(object->extendedData))->ctx = This->activeContext;
1229 if(GL_SUPPORT(ARB_OCCLUSION_QUERY)) {
1230 TRACE("(%p) Allocating data for an occlusion query\n", This);
1231 GL_EXTCALL(glGenQueriesARB(1, &((WineQueryOcclusionData *)(object->extendedData))->queryId));
1232 break;
1234 case WINED3DQUERYTYPE_EVENT:
1235 object->extendedData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WineQueryEventData));
1236 ((WineQueryEventData *)(object->extendedData))->ctx = This->activeContext;
1238 if(GL_SUPPORT(APPLE_FENCE)) {
1239 GL_EXTCALL(glGenFencesAPPLE(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1240 checkGLcall("glGenFencesAPPLE");
1241 } else if(GL_SUPPORT(NV_FENCE)) {
1242 GL_EXTCALL(glGenFencesNV(1, &((WineQueryEventData *)(object->extendedData))->fenceId));
1243 checkGLcall("glGenFencesNV");
1245 break;
1247 case WINED3DQUERYTYPE_VCACHE:
1248 case WINED3DQUERYTYPE_RESOURCEMANAGER:
1249 case WINED3DQUERYTYPE_VERTEXSTATS:
1250 case WINED3DQUERYTYPE_TIMESTAMP:
1251 case WINED3DQUERYTYPE_TIMESTAMPDISJOINT:
1252 case WINED3DQUERYTYPE_TIMESTAMPFREQ:
1253 case WINED3DQUERYTYPE_PIPELINETIMINGS:
1254 case WINED3DQUERYTYPE_INTERFACETIMINGS:
1255 case WINED3DQUERYTYPE_VERTEXTIMINGS:
1256 case WINED3DQUERYTYPE_PIXELTIMINGS:
1257 case WINED3DQUERYTYPE_BANDWIDTHTIMINGS:
1258 case WINED3DQUERYTYPE_CACHEUTILIZATION:
1259 default:
1260 object->extendedData = 0;
1261 FIXME("(%p) Unhandled query type %d\n",This , Type);
1263 TRACE("(%p) : Created Query %p\n", This, object);
1264 return WINED3D_OK;
1267 /*****************************************************************************
1268 * IWineD3DDeviceImpl_SetupFullscreenWindow
1270 * Helper function that modifies a HWND's Style and ExStyle for proper
1271 * fullscreen use.
1273 * Params:
1274 * iface: Pointer to the IWineD3DDevice interface
1275 * window: Window to setup
1277 *****************************************************************************/
1278 static LONG fullscreen_style(LONG orig_style) {
1279 LONG style = orig_style;
1280 style &= ~WS_CAPTION;
1281 style &= ~WS_THICKFRAME;
1283 /* Make sure the window is managed, otherwise we won't get keyboard input */
1284 style |= WS_POPUP | WS_SYSMENU;
1286 return style;
1289 static LONG fullscreen_exStyle(LONG orig_exStyle) {
1290 LONG exStyle = orig_exStyle;
1292 /* Filter out window decorations */
1293 exStyle &= ~WS_EX_WINDOWEDGE;
1294 exStyle &= ~WS_EX_CLIENTEDGE;
1296 return exStyle;
1299 static void WINAPI IWineD3DDeviceImpl_SetupFullscreenWindow(IWineD3DDevice *iface, HWND window, UINT w, UINT h) {
1300 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1302 LONG style, exStyle;
1303 /* Don't do anything if an original style is stored.
1304 * That shouldn't happen
1306 TRACE("(%p): Setting up window %p for exclusive mode\n", This, window);
1307 if (This->style || This->exStyle) {
1308 ERR("(%p): Want to change the window parameters of HWND %p, but "
1309 "another style is stored for restoration afterwards\n", This, window);
1312 /* Get the parameters and save them */
1313 style = GetWindowLongW(window, GWL_STYLE);
1314 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1315 This->style = style;
1316 This->exStyle = exStyle;
1318 style = fullscreen_style(style);
1319 exStyle = fullscreen_exStyle(exStyle);
1321 TRACE("Old style was %08x,%08x, setting to %08x,%08x\n",
1322 This->style, This->exStyle, style, exStyle);
1324 SetWindowLongW(window, GWL_STYLE, style);
1325 SetWindowLongW(window, GWL_EXSTYLE, exStyle);
1327 /* Inform the window about the update. */
1328 SetWindowPos(window, HWND_TOP, 0, 0,
1329 w, h, SWP_FRAMECHANGED | SWP_SHOWWINDOW);
1332 /*****************************************************************************
1333 * IWineD3DDeviceImpl_RestoreWindow
1335 * Helper function that restores a windows' properties when taking it out
1336 * of fullscreen mode
1338 * Params:
1339 * iface: Pointer to the IWineD3DDevice interface
1340 * window: Window to setup
1342 *****************************************************************************/
1343 static void WINAPI IWineD3DDeviceImpl_RestoreWindow(IWineD3DDevice *iface, HWND window) {
1344 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1345 LONG style, exStyle;
1347 /* This could be a DDSCL_NORMAL -> DDSCL_NORMAL
1348 * switch, do nothing
1350 if (!This->style && !This->exStyle) return;
1352 TRACE("(%p): Restoring window settings of window %p to %08x, %08x\n",
1353 This, window, This->style, This->exStyle);
1355 style = GetWindowLongW(window, GWL_STYLE);
1356 exStyle = GetWindowLongW(window, GWL_EXSTYLE);
1358 /* Only restore the style if the application didn't modify it during the fullscreen phase.
1359 * Some applications change it before calling Reset() when switching between windowed and
1360 * fullscreen modes(HL2), some depend on the original style(Eve Online)
1362 if(style == fullscreen_style(This->style) &&
1363 exStyle == fullscreen_style(This->exStyle)) {
1364 SetWindowLongW(window, GWL_STYLE, This->style);
1365 SetWindowLongW(window, GWL_EXSTYLE, This->exStyle);
1368 /* Delete the old values */
1369 This->style = 0;
1370 This->exStyle = 0;
1372 /* Inform the window about the update */
1373 SetWindowPos(window, 0 /* InsertAfter, ignored */,
1374 0, 0, 0, 0, /* Pos, Size, ignored */
1375 SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
1378 /* example at http://www.fairyengine.com/articles/dxmultiviews.htm */
1379 static HRESULT WINAPI IWineD3DDeviceImpl_CreateAdditionalSwapChain(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, IWineD3DSwapChain** ppSwapChain,
1380 IUnknown* parent,
1381 D3DCB_CREATERENDERTARGETFN D3DCB_CreateRenderTarget,
1382 D3DCB_CREATEDEPTHSTENCILSURFACEFN D3DCB_CreateDepthStencil,
1383 WINED3DSURFTYPE surface_type) {
1384 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1386 HDC hDc;
1387 IWineD3DSwapChainImpl *object; /** NOTE: impl ref allowed since this is a create function **/
1388 HRESULT hr = WINED3D_OK;
1389 IUnknown *bufferParent;
1390 BOOL displaymode_set = FALSE;
1391 WINED3DDISPLAYMODE Mode;
1392 const StaticPixelFormatDesc *formatDesc;
1394 TRACE("(%p) : Created Additional Swap Chain\n", This);
1396 /** FIXME: Test under windows to find out what the life cycle of a swap chain is,
1397 * does a device hold a reference to a swap chain giving them a lifetime of the device
1398 * or does the swap chain notify the device of its destruction.
1399 *******************************/
1401 /* Check the params */
1402 if(pPresentationParameters->BackBufferCount > WINED3DPRESENT_BACK_BUFFER_MAX) {
1403 ERR("App requested %d back buffers, this is not supported for now\n", pPresentationParameters->BackBufferCount);
1404 return WINED3DERR_INVALIDCALL;
1405 } else if (pPresentationParameters->BackBufferCount > 1) {
1406 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");
1409 D3DCREATEOBJECTINSTANCE(object, SwapChain)
1410 switch(surface_type) {
1411 case SURFACE_GDI:
1412 object->lpVtbl = &IWineGDISwapChain_Vtbl;
1413 break;
1414 case SURFACE_OPENGL:
1415 object->lpVtbl = &IWineD3DSwapChain_Vtbl;
1416 break;
1417 case SURFACE_UNKNOWN:
1418 FIXME("Caller tried to create a SURFACE_UNKNOWN swapchain\n");
1419 return WINED3DERR_INVALIDCALL;
1422 /*********************
1423 * Lookup the window Handle and the relating X window handle
1424 ********************/
1426 /* Setup hwnd we are using, plus which display this equates to */
1427 object->win_handle = pPresentationParameters->hDeviceWindow;
1428 if (!object->win_handle) {
1429 object->win_handle = This->createParms.hFocusWindow;
1431 if(!pPresentationParameters->Windowed && object->win_handle) {
1432 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, object->win_handle,
1433 pPresentationParameters->BackBufferWidth,
1434 pPresentationParameters->BackBufferHeight);
1437 hDc = GetDC(object->win_handle);
1438 TRACE("Using hDc %p\n", hDc);
1440 if (NULL == hDc) {
1441 WARN("Failed to get a HDc for Window %p\n", object->win_handle);
1442 return WINED3DERR_NOTAVAILABLE;
1445 /* Get info on the current display setup */
1446 IWineD3D_GetAdapterDisplayMode(This->wineD3D, This->adapter->num, &Mode);
1447 object->orig_width = Mode.Width;
1448 object->orig_height = Mode.Height;
1449 object->orig_fmt = Mode.Format;
1450 formatDesc = getFormatDescEntry(Mode.Format, NULL, NULL);
1452 /** MSDN: If Windowed is TRUE and either of the BackBufferWidth/Height values is zero,
1453 * then the corresponding dimension of the client area of the hDeviceWindow
1454 * (or the focus window, if hDeviceWindow is NULL) is taken.
1455 **********************/
1457 if (pPresentationParameters->Windowed &&
1458 ((pPresentationParameters->BackBufferWidth == 0) ||
1459 (pPresentationParameters->BackBufferHeight == 0) ||
1460 (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN))) {
1462 RECT Rect;
1463 GetClientRect(object->win_handle, &Rect);
1465 if (pPresentationParameters->BackBufferWidth == 0) {
1466 pPresentationParameters->BackBufferWidth = Rect.right;
1467 TRACE("Updating width to %d\n", pPresentationParameters->BackBufferWidth);
1469 if (pPresentationParameters->BackBufferHeight == 0) {
1470 pPresentationParameters->BackBufferHeight = Rect.bottom;
1471 TRACE("Updating height to %d\n", pPresentationParameters->BackBufferHeight);
1473 if (pPresentationParameters->BackBufferFormat == WINED3DFMT_UNKNOWN) {
1474 pPresentationParameters->BackBufferFormat = object->orig_fmt;
1475 TRACE("Updating format to %s\n", debug_d3dformat(object->orig_fmt));
1479 /* Put the correct figures in the presentation parameters */
1480 TRACE("Copying across presentation parameters\n");
1481 object->presentParms = *pPresentationParameters;
1483 TRACE("calling rendertarget CB\n");
1484 hr = D3DCB_CreateRenderTarget(This->parent,
1485 parent,
1486 object->presentParms.BackBufferWidth,
1487 object->presentParms.BackBufferHeight,
1488 object->presentParms.BackBufferFormat,
1489 object->presentParms.MultiSampleType,
1490 object->presentParms.MultiSampleQuality,
1491 TRUE /* Lockable */,
1492 &object->frontBuffer,
1493 NULL /* pShared (always null)*/);
1494 if (object->frontBuffer != NULL) {
1495 IWineD3DSurface_SetContainer(object->frontBuffer, (IWineD3DBase *)object);
1496 if(surface_type == SURFACE_OPENGL) {
1497 IWineD3DSurface_ModifyLocation(object->frontBuffer, SFLAG_INDRAWABLE, TRUE);
1499 } else {
1500 ERR("Failed to create the front buffer\n");
1501 goto error;
1504 /*********************
1505 * Windowed / Fullscreen
1506 *******************/
1509 * TODO: MSDN says that we are only allowed one fullscreen swapchain per device,
1510 * so we should really check to see if there is a fullscreen swapchain already
1511 * I think Windows and X have different ideas about fullscreen, does a single head count as full screen?
1512 **************************************/
1514 if (!pPresentationParameters->Windowed) {
1515 WINED3DDISPLAYMODE mode;
1518 /* Change the display settings */
1519 mode.Width = pPresentationParameters->BackBufferWidth;
1520 mode.Height = pPresentationParameters->BackBufferHeight;
1521 mode.Format = pPresentationParameters->BackBufferFormat;
1522 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
1524 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
1525 displaymode_set = TRUE;
1529 * Create an opengl context for the display visual
1530 * NOTE: the visual is chosen as the window is created and the glcontext cannot
1531 * use different properties after that point in time. FIXME: How to handle when requested format
1532 * doesn't match actual visual? Cannot choose one here - code removed as it ONLY works if the one
1533 * it chooses is identical to the one already being used!
1534 **********************************/
1535 /** FIXME: Handle stencil appropriately via EnableAutoDepthStencil / AutoDepthStencilFormat **/
1537 object->context = HeapAlloc(GetProcessHeap(), 0, sizeof(object->context));
1538 if(!object->context)
1539 return E_OUTOFMEMORY;
1540 object->num_contexts = 1;
1542 if(surface_type == SURFACE_OPENGL) {
1543 object->context[0] = CreateContext(This, (IWineD3DSurfaceImpl *) object->frontBuffer, object->win_handle, FALSE /* pbuffer */, pPresentationParameters);
1544 if (!object->context[0]) {
1545 ERR("Failed to create a new context\n");
1546 hr = WINED3DERR_NOTAVAILABLE;
1547 goto error;
1548 } else {
1549 TRACE("Context created (HWND=%p, glContext=%p)\n",
1550 object->win_handle, object->context[0]->glCtx);
1554 /*********************
1555 * Create the back, front and stencil buffers
1556 *******************/
1557 if(object->presentParms.BackBufferCount > 0) {
1558 int i;
1560 object->backBuffer = HeapAlloc(GetProcessHeap(), 0, sizeof(IWineD3DSurface *) * object->presentParms.BackBufferCount);
1561 if(!object->backBuffer) {
1562 ERR("Out of memory\n");
1563 hr = E_OUTOFMEMORY;
1564 goto error;
1567 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1568 TRACE("calling rendertarget CB\n");
1569 hr = D3DCB_CreateRenderTarget(This->parent,
1570 parent,
1571 object->presentParms.BackBufferWidth,
1572 object->presentParms.BackBufferHeight,
1573 object->presentParms.BackBufferFormat,
1574 object->presentParms.MultiSampleType,
1575 object->presentParms.MultiSampleQuality,
1576 TRUE /* Lockable */,
1577 &object->backBuffer[i],
1578 NULL /* pShared (always null)*/);
1579 if(hr == WINED3D_OK && object->backBuffer[i]) {
1580 IWineD3DSurface_SetContainer(object->backBuffer[i], (IWineD3DBase *)object);
1581 } else {
1582 ERR("Cannot create new back buffer\n");
1583 goto error;
1585 if(surface_type == SURFACE_OPENGL) {
1586 ENTER_GL();
1587 glDrawBuffer(GL_BACK);
1588 checkGLcall("glDrawBuffer(GL_BACK)");
1589 LEAVE_GL();
1592 } else {
1593 object->backBuffer = NULL;
1595 /* Single buffering - draw to front buffer */
1596 if(surface_type == SURFACE_OPENGL) {
1597 ENTER_GL();
1598 glDrawBuffer(GL_FRONT);
1599 checkGLcall("glDrawBuffer(GL_FRONT)");
1600 LEAVE_GL();
1604 /* Under directX swapchains share the depth stencil, so only create one depth-stencil */
1605 if (pPresentationParameters->EnableAutoDepthStencil && hr == WINED3D_OK && surface_type == SURFACE_OPENGL) {
1606 TRACE("Creating depth stencil buffer\n");
1607 if (This->auto_depth_stencil_buffer == NULL ) {
1608 hr = D3DCB_CreateDepthStencil(This->parent,
1609 parent,
1610 object->presentParms.BackBufferWidth,
1611 object->presentParms.BackBufferHeight,
1612 object->presentParms.AutoDepthStencilFormat,
1613 object->presentParms.MultiSampleType,
1614 object->presentParms.MultiSampleQuality,
1615 FALSE /* FIXME: Discard */,
1616 &This->auto_depth_stencil_buffer,
1617 NULL /* pShared (always null)*/ );
1618 if (This->auto_depth_stencil_buffer != NULL)
1619 IWineD3DSurface_SetContainer(This->auto_depth_stencil_buffer, 0);
1622 /** TODO: A check on width, height and multisample types
1623 *(since the zbuffer must be at least as large as the render target and have the same multisample parameters)
1624 ****************************/
1625 object->wantsDepthStencilBuffer = TRUE;
1626 } else {
1627 object->wantsDepthStencilBuffer = FALSE;
1630 IWineD3DSwapChain_GetGammaRamp((IWineD3DSwapChain *) object, &object->orig_gamma);
1632 TRACE("Created swapchain %p\n", object);
1633 TRACE("FrontBuf @ %p, BackBuf @ %p, DepthStencil %d\n",object->frontBuffer, object->backBuffer ? object->backBuffer[0] : NULL, object->wantsDepthStencilBuffer);
1634 return WINED3D_OK;
1636 error:
1637 if (displaymode_set) {
1638 DEVMODEW devmode;
1639 RECT clip_rc;
1641 SetRect(&clip_rc, 0, 0, object->orig_width, object->orig_height);
1642 ClipCursor(NULL);
1644 /* Change the display settings */
1645 memset(&devmode, 0, sizeof(devmode));
1646 devmode.dmSize = sizeof(devmode);
1647 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
1648 devmode.dmBitsPerPel = formatDesc->bpp * 8;
1649 devmode.dmPelsWidth = object->orig_width;
1650 devmode.dmPelsHeight = object->orig_height;
1651 ChangeDisplaySettingsExW(This->adapter->DeviceName, &devmode, NULL, CDS_FULLSCREEN, NULL);
1654 if (object->backBuffer) {
1655 int i;
1656 for(i = 0; i < object->presentParms.BackBufferCount; i++) {
1657 if(object->backBuffer[i]) {
1658 IWineD3DSurface_GetParent(object->backBuffer[i], &bufferParent);
1659 IUnknown_Release(bufferParent); /* once for the get parent */
1660 if (IUnknown_Release(bufferParent) > 0) {
1661 FIXME("(%p) Something's still holding the back buffer\n",This);
1665 HeapFree(GetProcessHeap(), 0, object->backBuffer);
1666 object->backBuffer = NULL;
1668 if(object->context[0])
1669 DestroyContext(This, object->context[0]);
1670 if(object->frontBuffer) {
1671 IWineD3DSurface_GetParent(object->frontBuffer, &bufferParent);
1672 IUnknown_Release(bufferParent); /* once for the get parent */
1673 if (IUnknown_Release(bufferParent) > 0) {
1674 FIXME("(%p) Something's still holding the front buffer\n",This);
1677 HeapFree(GetProcessHeap(), 0, object);
1678 return hr;
1681 /** NOTE: These are ahead of the other getters and setters to save using a forward declaration **/
1682 static UINT WINAPI IWineD3DDeviceImpl_GetNumberOfSwapChains(IWineD3DDevice *iface) {
1683 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1684 TRACE("(%p)\n", This);
1686 return This->NumberOfSwapChains;
1689 static HRESULT WINAPI IWineD3DDeviceImpl_GetSwapChain(IWineD3DDevice *iface, UINT iSwapChain, IWineD3DSwapChain **pSwapChain) {
1690 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1691 TRACE("(%p) : swapchain %d\n", This, iSwapChain);
1693 if(iSwapChain < This->NumberOfSwapChains) {
1694 *pSwapChain = This->swapchains[iSwapChain];
1695 IWineD3DSwapChain_AddRef(*pSwapChain);
1696 TRACE("(%p) returning %p\n", This, *pSwapChain);
1697 return WINED3D_OK;
1698 } else {
1699 TRACE("Swapchain out of range\n");
1700 *pSwapChain = NULL;
1701 return WINED3DERR_INVALIDCALL;
1705 /*****
1706 * Vertex Declaration
1707 *****/
1708 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration,
1709 IUnknown *parent, const WINED3DVERTEXELEMENT *elements, UINT element_count) {
1710 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1711 IWineD3DVertexDeclarationImpl *object = NULL;
1712 HRESULT hr = WINED3D_OK;
1714 TRACE("(%p) : directXVersion %u, elements %p, element_count %d, ppDecl=%p\n",
1715 This, ((IWineD3DImpl *)This->wineD3D)->dxVersion, elements, element_count, ppVertexDeclaration);
1717 D3DCREATEOBJECTINSTANCE(object, VertexDeclaration)
1719 hr = IWineD3DVertexDeclaration_SetDeclaration((IWineD3DVertexDeclaration *)object, elements, element_count);
1720 if(FAILED(hr)) {
1721 *ppVertexDeclaration = NULL;
1722 HeapFree(GetProcessHeap(), 0, object);
1725 return hr;
1728 static unsigned int ConvertFvfToDeclaration(IWineD3DDeviceImpl *This, /* For the GL info, which has the type table */
1729 DWORD fvf, WINED3DVERTEXELEMENT** ppVertexElements) {
1731 unsigned int idx, idx2;
1732 unsigned int offset;
1733 BOOL has_pos = (fvf & WINED3DFVF_POSITION_MASK) != 0;
1734 BOOL has_blend = (fvf & WINED3DFVF_XYZB5) > WINED3DFVF_XYZRHW;
1735 BOOL has_blend_idx = has_blend &&
1736 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB5) ||
1737 (fvf & WINED3DFVF_LASTBETA_D3DCOLOR) ||
1738 (fvf & WINED3DFVF_LASTBETA_UBYTE4));
1739 BOOL has_normal = (fvf & WINED3DFVF_NORMAL) != 0;
1740 BOOL has_psize = (fvf & WINED3DFVF_PSIZE) != 0;
1741 BOOL has_diffuse = (fvf & WINED3DFVF_DIFFUSE) != 0;
1742 BOOL has_specular = (fvf & WINED3DFVF_SPECULAR) !=0;
1744 DWORD num_textures = (fvf & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
1745 DWORD texcoords = (fvf & 0xFFFF0000) >> 16;
1747 WINED3DVERTEXELEMENT end_element = WINED3DDECL_END();
1748 WINED3DVERTEXELEMENT *elements = NULL;
1750 unsigned int size;
1751 DWORD num_blends = 1 + (((fvf & WINED3DFVF_XYZB5) - WINED3DFVF_XYZB1) >> 1);
1752 if (has_blend_idx) num_blends--;
1754 /* Compute declaration size */
1755 size = has_pos + (has_blend && num_blends > 0) + has_blend_idx + has_normal +
1756 has_psize + has_diffuse + has_specular + num_textures + 1;
1758 /* convert the declaration */
1759 elements = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WINED3DVERTEXELEMENT));
1760 if (!elements)
1761 return 0;
1763 elements[size-1] = end_element;
1764 idx = 0;
1765 if (has_pos) {
1766 if (!has_blend && (fvf & WINED3DFVF_XYZRHW)) {
1767 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1768 elements[idx].Usage = WINED3DDECLUSAGE_POSITIONT;
1770 else {
1771 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1772 elements[idx].Usage = WINED3DDECLUSAGE_POSITION;
1774 elements[idx].UsageIndex = 0;
1775 idx++;
1777 if (has_blend && (num_blends > 0)) {
1778 if (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR))
1779 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1780 else
1781 elements[idx].Type = WINED3DDECLTYPE_FLOAT1 + num_blends - 1;
1782 elements[idx].Usage = WINED3DDECLUSAGE_BLENDWEIGHT;
1783 elements[idx].UsageIndex = 0;
1784 idx++;
1786 if (has_blend_idx) {
1787 if (fvf & WINED3DFVF_LASTBETA_UBYTE4 ||
1788 (((fvf & WINED3DFVF_XYZB5) == WINED3DFVF_XYZB2) && (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)))
1789 elements[idx].Type = WINED3DDECLTYPE_UBYTE4;
1790 else if (fvf & WINED3DFVF_LASTBETA_D3DCOLOR)
1791 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1792 else
1793 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1794 elements[idx].Usage = WINED3DDECLUSAGE_BLENDINDICES;
1795 elements[idx].UsageIndex = 0;
1796 idx++;
1798 if (has_normal) {
1799 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1800 elements[idx].Usage = WINED3DDECLUSAGE_NORMAL;
1801 elements[idx].UsageIndex = 0;
1802 idx++;
1804 if (has_psize) {
1805 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1806 elements[idx].Usage = WINED3DDECLUSAGE_PSIZE;
1807 elements[idx].UsageIndex = 0;
1808 idx++;
1810 if (has_diffuse) {
1811 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1812 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1813 elements[idx].UsageIndex = 0;
1814 idx++;
1816 if (has_specular) {
1817 elements[idx].Type = WINED3DDECLTYPE_D3DCOLOR;
1818 elements[idx].Usage = WINED3DDECLUSAGE_COLOR;
1819 elements[idx].UsageIndex = 1;
1820 idx++;
1822 for (idx2 = 0; idx2 < num_textures; idx2++) {
1823 unsigned int numcoords = (texcoords >> (idx2*2)) & 0x03;
1824 switch (numcoords) {
1825 case WINED3DFVF_TEXTUREFORMAT1:
1826 elements[idx].Type = WINED3DDECLTYPE_FLOAT1;
1827 break;
1828 case WINED3DFVF_TEXTUREFORMAT2:
1829 elements[idx].Type = WINED3DDECLTYPE_FLOAT2;
1830 break;
1831 case WINED3DFVF_TEXTUREFORMAT3:
1832 elements[idx].Type = WINED3DDECLTYPE_FLOAT3;
1833 break;
1834 case WINED3DFVF_TEXTUREFORMAT4:
1835 elements[idx].Type = WINED3DDECLTYPE_FLOAT4;
1836 break;
1838 elements[idx].Usage = WINED3DDECLUSAGE_TEXCOORD;
1839 elements[idx].UsageIndex = idx2;
1840 idx++;
1843 /* Now compute offsets, and initialize the rest of the fields */
1844 for (idx = 0, offset = 0; idx < size-1; idx++) {
1845 elements[idx].Stream = 0;
1846 elements[idx].Method = WINED3DDECLMETHOD_DEFAULT;
1847 elements[idx].Offset = offset;
1848 offset += WINED3D_ATR_SIZE(elements[idx].Type) * WINED3D_ATR_TYPESIZE(elements[idx].Type);
1851 *ppVertexElements = elements;
1852 return size;
1855 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppVertexDeclaration, IUnknown *Parent, DWORD Fvf) {
1856 WINED3DVERTEXELEMENT* elements = NULL;
1857 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1858 unsigned int size;
1859 DWORD hr;
1861 size = ConvertFvfToDeclaration(This, Fvf, &elements);
1862 if (size == 0) return WINED3DERR_OUTOFVIDEOMEMORY;
1864 hr = IWineD3DDevice_CreateVertexDeclaration(iface, ppVertexDeclaration, Parent, elements, size);
1865 HeapFree(GetProcessHeap(), 0, elements);
1866 if (hr != S_OK) return hr;
1868 return WINED3D_OK;
1871 static HRESULT WINAPI IWineD3DDeviceImpl_CreateVertexShader(IWineD3DDevice *iface, IWineD3DVertexDeclaration *vertex_declaration, CONST DWORD *pFunction, IWineD3DVertexShader **ppVertexShader, IUnknown *parent) {
1872 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1873 IWineD3DVertexShaderImpl *object; /* NOTE: impl usage is ok, this is a create */
1874 HRESULT hr = WINED3D_OK;
1875 D3DCREATESHADEROBJECTINSTANCE(object, VertexShader)
1876 object->baseShader.shader_ins = IWineD3DVertexShaderImpl_shader_ins;
1878 TRACE("(%p) : Created Vertex shader %p\n", This, *ppVertexShader);
1880 if (vertex_declaration) {
1881 IWineD3DVertexShader_FakeSemantics(*ppVertexShader, vertex_declaration);
1884 hr = IWineD3DVertexShader_SetFunction(*ppVertexShader, pFunction);
1886 if (WINED3D_OK != hr) {
1887 FIXME("(%p) : Failed to set the function, returning WINED3DERR_INVALIDCALL\n", iface);
1888 IWineD3DVertexShader_Release(*ppVertexShader);
1889 return WINED3DERR_INVALIDCALL;
1891 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1893 return WINED3D_OK;
1896 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePixelShader(IWineD3DDevice *iface, CONST DWORD *pFunction, IWineD3DPixelShader **ppPixelShader, IUnknown *parent) {
1897 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
1898 IWineD3DPixelShaderImpl *object; /* NOTE: impl allowed, this is a create */
1899 HRESULT hr = WINED3D_OK;
1901 D3DCREATESHADEROBJECTINSTANCE(object, PixelShader)
1902 object->baseShader.shader_ins = IWineD3DPixelShaderImpl_shader_ins;
1903 hr = IWineD3DPixelShader_SetFunction(*ppPixelShader, pFunction);
1904 if (WINED3D_OK == hr) {
1905 TRACE("(%p) : Created Pixel shader %p\n", This, *ppPixelShader);
1906 list_add_head(&This->shaders, &object->baseShader.shader_list_entry);
1907 } else {
1908 WARN("(%p) : Failed to create pixel shader\n", This);
1911 return hr;
1914 static HRESULT WINAPI IWineD3DDeviceImpl_CreatePalette(IWineD3DDevice *iface, DWORD Flags, PALETTEENTRY *PalEnt, IWineD3DPalette **Palette, IUnknown *Parent) {
1915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
1916 IWineD3DPaletteImpl *object;
1917 HRESULT hr;
1918 TRACE("(%p)->(%x, %p, %p, %p)\n", This, Flags, PalEnt, Palette, Parent);
1920 /* Create the new object */
1921 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DPaletteImpl));
1922 if(!object) {
1923 ERR("Out of memory when allocating memory for a IWineD3DPalette implementation\n");
1924 return E_OUTOFMEMORY;
1927 object->lpVtbl = &IWineD3DPalette_Vtbl;
1928 object->ref = 1;
1929 object->Flags = Flags;
1930 object->parent = Parent;
1931 object->wineD3DDevice = This;
1932 object->palNumEntries = IWineD3DPaletteImpl_Size(Flags);
1934 object->hpal = CreatePalette((const LOGPALETTE*)&(object->palVersion));
1936 if(!object->hpal) {
1937 HeapFree( GetProcessHeap(), 0, object);
1938 return E_OUTOFMEMORY;
1941 hr = IWineD3DPalette_SetEntries((IWineD3DPalette *) object, 0, 0, IWineD3DPaletteImpl_Size(Flags), PalEnt);
1942 if(FAILED(hr)) {
1943 IWineD3DPalette_Release((IWineD3DPalette *) object);
1944 return hr;
1947 *Palette = (IWineD3DPalette *) object;
1949 return WINED3D_OK;
1952 static void IWineD3DDeviceImpl_LoadLogo(IWineD3DDeviceImpl *This, const char *filename) {
1953 HBITMAP hbm;
1954 BITMAP bm;
1955 HRESULT hr;
1956 HDC dcb = NULL, dcs = NULL;
1957 WINEDDCOLORKEY colorkey;
1959 hbm = (HBITMAP) LoadImageA(NULL, filename, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
1960 if(hbm)
1962 GetObjectA(hbm, sizeof(BITMAP), &bm);
1963 dcb = CreateCompatibleDC(NULL);
1964 if(!dcb) goto out;
1965 SelectObject(dcb, hbm);
1967 else
1969 /* Create a 32x32 white surface to indicate that wined3d is used, but the specified image
1970 * couldn't be loaded
1972 memset(&bm, 0, sizeof(bm));
1973 bm.bmWidth = 32;
1974 bm.bmHeight = 32;
1977 hr = IWineD3DDevice_CreateSurface((IWineD3DDevice *) This, bm.bmWidth, bm.bmHeight, WINED3DFMT_R5G6B5,
1978 TRUE, FALSE, 0, &This->logo_surface, WINED3DRTYPE_SURFACE, 0,
1979 WINED3DPOOL_DEFAULT, WINED3DMULTISAMPLE_NONE, 0, NULL, SURFACE_OPENGL, NULL);
1980 if(FAILED(hr)) {
1981 ERR("Wine logo requested, but failed to create surface\n");
1982 goto out;
1985 if(dcb) {
1986 hr = IWineD3DSurface_GetDC(This->logo_surface, &dcs);
1987 if(FAILED(hr)) goto out;
1988 BitBlt(dcs, 0, 0, bm.bmWidth, bm.bmHeight, dcb, 0, 0, SRCCOPY);
1989 IWineD3DSurface_ReleaseDC(This->logo_surface, dcs);
1991 colorkey.dwColorSpaceLowValue = 0;
1992 colorkey.dwColorSpaceHighValue = 0;
1993 IWineD3DSurface_SetColorKey(This->logo_surface, WINEDDCKEY_SRCBLT, &colorkey);
1994 } else {
1995 /* Fill the surface with a white color to show that wined3d is there */
1996 IWineD3DDevice_ColorFill((IWineD3DDevice *) This, This->logo_surface, NULL, 0xffffffff);
1999 out:
2000 if(dcb) {
2001 DeleteDC(dcb);
2003 if(hbm) {
2004 DeleteObject(hbm);
2006 return;
2009 static void create_dummy_textures(IWineD3DDeviceImpl *This) {
2010 unsigned int i;
2011 /* Under DirectX you can have texture stage operations even if no texture is
2012 bound, whereas opengl will only do texture operations when a valid texture is
2013 bound. We emulate this by creating dummy textures and binding them to each
2014 texture stage, but disable all stages by default. Hence if a stage is enabled
2015 then the default texture will kick in until replaced by a SetTexture call */
2016 ENTER_GL();
2018 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2019 /* The dummy texture does not have client storage backing */
2020 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
2021 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
2023 for (i = 0; i < GL_LIMITS(textures); i++) {
2024 GLubyte white = 255;
2026 /* Make appropriate texture active */
2027 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
2028 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB + i));
2029 checkGLcall("glActiveTextureARB");
2030 } else if (i > 0) {
2031 FIXME("Program using multiple concurrent textures which this opengl implementation doesn't support\n");
2034 /* Generate an opengl texture name */
2035 glGenTextures(1, &This->dummyTextureName[i]);
2036 checkGLcall("glGenTextures");
2037 TRACE("Dummy Texture %d given name %d\n", i, This->dummyTextureName[i]);
2039 /* Generate a dummy 2d texture (not using 1d because they cause many
2040 * DRI drivers fall back to sw) */
2041 This->stateBlock->textureDimensions[i] = GL_TEXTURE_2D;
2042 glBindTexture(GL_TEXTURE_2D, This->dummyTextureName[i]);
2043 checkGLcall("glBindTexture");
2045 glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 1, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, &white);
2046 checkGLcall("glTexImage2D");
2048 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
2049 /* Reenable because if supported it is enabled by default */
2050 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
2051 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
2054 LEAVE_GL();
2057 static HRESULT WINAPI IWineD3DDeviceImpl_Init3D(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2058 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2059 IWineD3DSwapChainImpl *swapchain = NULL;
2060 HRESULT hr;
2061 DWORD state;
2062 unsigned int i;
2064 TRACE("(%p)->(%p,%p)\n", This, pPresentationParameters, D3DCB_CreateAdditionalSwapChain);
2065 if(This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2066 if(!This->adapter->opengl) return WINED3DERR_INVALIDCALL;
2068 /* TODO: Test if OpenGL is compiled in and loaded */
2070 TRACE("(%p) : Creating stateblock\n", This);
2071 /* Creating the startup stateBlock - Note Special Case: 0 => Don't fill in yet! */
2072 hr = IWineD3DDevice_CreateStateBlock(iface,
2073 WINED3DSBT_INIT,
2074 (IWineD3DStateBlock **)&This->stateBlock,
2075 NULL);
2076 if (WINED3D_OK != hr) { /* Note: No parent needed for initial internal stateblock */
2077 WARN("Failed to create stateblock\n");
2078 goto err_out;
2080 TRACE("(%p) : Created stateblock (%p)\n", This, This->stateBlock);
2081 This->updateStateBlock = This->stateBlock;
2082 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
2084 hr = allocate_shader_constants(This->updateStateBlock);
2085 if (WINED3D_OK != hr) {
2086 goto err_out;
2089 This->render_targets = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *) * GL_LIMITS(buffers));
2090 This->draw_buffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(GLenum) * GL_LIMITS(buffers));
2092 This->NumberOfPalettes = 1;
2093 This->palettes = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PALETTEENTRY*));
2094 if(!This->palettes || !This->render_targets || !This->draw_buffers) {
2095 ERR("Out of memory!\n");
2096 goto err_out;
2098 This->palettes[0] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
2099 if(!This->palettes[0]) {
2100 ERR("Out of memory!\n");
2101 goto err_out;
2103 for (i = 0; i < 256; ++i) {
2104 This->palettes[0][i].peRed = 0xFF;
2105 This->palettes[0][i].peGreen = 0xFF;
2106 This->palettes[0][i].peBlue = 0xFF;
2107 This->palettes[0][i].peFlags = 0xFF;
2109 This->currentPalette = 0;
2111 /* Initialize the texture unit mapping to a 1:1 mapping */
2112 for (state = 0; state < MAX_COMBINED_SAMPLERS; ++state) {
2113 if (state < GL_LIMITS(fragment_samplers)) {
2114 This->texUnitMap[state] = state;
2115 This->rev_tex_unit_map[state] = state;
2116 } else {
2117 This->texUnitMap[state] = -1;
2118 This->rev_tex_unit_map[state] = -1;
2122 /* Setup the implicit swapchain */
2123 TRACE("Creating implicit swapchain\n");
2124 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2125 if (FAILED(hr) || !swapchain) {
2126 WARN("Failed to create implicit swapchain\n");
2127 goto err_out;
2130 This->NumberOfSwapChains = 1;
2131 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2132 if(!This->swapchains) {
2133 ERR("Out of memory!\n");
2134 goto err_out;
2136 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2138 if(swapchain->backBuffer && swapchain->backBuffer[0]) {
2139 TRACE("Setting rendertarget to %p\n", swapchain->backBuffer);
2140 This->render_targets[0] = swapchain->backBuffer[0];
2141 This->lastActiveRenderTarget = swapchain->backBuffer[0];
2143 else {
2144 TRACE("Setting rendertarget to %p\n", swapchain->frontBuffer);
2145 This->render_targets[0] = swapchain->frontBuffer;
2146 This->lastActiveRenderTarget = swapchain->frontBuffer;
2148 IWineD3DSurface_AddRef(This->render_targets[0]);
2149 This->activeContext = swapchain->context[0];
2150 This->lastThread = GetCurrentThreadId();
2152 /* Depth Stencil support */
2153 This->stencilBufferTarget = This->auto_depth_stencil_buffer;
2154 if (NULL != This->stencilBufferTarget) {
2155 IWineD3DSurface_AddRef(This->stencilBufferTarget);
2158 hr = This->shader_backend->shader_alloc_private(iface);
2159 if(FAILED(hr)) {
2160 TRACE("Shader private data couldn't be allocated\n");
2161 goto err_out;
2163 hr = This->frag_pipe->alloc_private(iface);
2164 if(FAILED(hr)) {
2165 TRACE("Fragment pipeline private data couldn't be allocated\n");
2166 goto err_out;
2168 hr = This->blitter->alloc_private(iface);
2169 if(FAILED(hr)) {
2170 TRACE("Blitter private data couldn't be allocated\n");
2171 goto err_out;
2174 /* Set up some starting GL setup */
2176 /* Setup all the devices defaults */
2177 IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *)This->stateBlock);
2178 create_dummy_textures(This);
2180 ENTER_GL();
2182 { /* Set a default viewport */
2183 WINED3DVIEWPORT vp;
2184 vp.X = 0;
2185 vp.Y = 0;
2186 vp.Width = pPresentationParameters->BackBufferWidth;
2187 vp.Height = pPresentationParameters->BackBufferHeight;
2188 vp.MinZ = 0.0f;
2189 vp.MaxZ = 1.0f;
2190 IWineD3DDevice_SetViewport((IWineD3DDevice *)This, &vp);
2193 /* Initialize the current view state */
2194 This->view_ident = 1;
2195 This->contexts[0]->last_was_rhw = 0;
2196 glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights);
2197 checkGLcall("glGetIntegerv(GL_MAX_LIGHTS, &This->maxConcurrentLights)");
2199 switch(wined3d_settings.offscreen_rendering_mode) {
2200 case ORM_FBO:
2201 case ORM_PBUFFER:
2202 This->offscreenBuffer = GL_BACK;
2203 break;
2205 case ORM_BACKBUFFER:
2207 if(This->activeContext->aux_buffers > 0) {
2208 TRACE("Using auxilliary buffer for offscreen rendering\n");
2209 This->offscreenBuffer = GL_AUX0;
2210 } else {
2211 TRACE("Using back buffer for offscreen rendering\n");
2212 This->offscreenBuffer = GL_BACK;
2217 TRACE("(%p) All defaults now set up, leaving Init3D with %p\n", This, This);
2218 LEAVE_GL();
2220 /* Clear the screen */
2221 IWineD3DDevice_Clear((IWineD3DDevice *) This, 0, NULL,
2222 WINED3DCLEAR_TARGET | pPresentationParameters->EnableAutoDepthStencil ? WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL : 0,
2223 0x00, 1.0, 0);
2225 This->d3d_initialized = TRUE;
2227 if(wined3d_settings.logo) {
2228 IWineD3DDeviceImpl_LoadLogo(This, wined3d_settings.logo);
2230 This->highest_dirty_ps_const = 0;
2231 This->highest_dirty_vs_const = 0;
2232 return WINED3D_OK;
2234 err_out:
2235 HeapFree(GetProcessHeap(), 0, This->render_targets);
2236 HeapFree(GetProcessHeap(), 0, This->draw_buffers);
2237 HeapFree(GetProcessHeap(), 0, This->swapchains);
2238 This->NumberOfSwapChains = 0;
2239 if(This->palettes) {
2240 HeapFree(GetProcessHeap(), 0, This->palettes[0]);
2241 HeapFree(GetProcessHeap(), 0, This->palettes);
2243 This->NumberOfPalettes = 0;
2244 if(swapchain) {
2245 IWineD3DSwapChain_Release( (IWineD3DSwapChain *) swapchain);
2247 if(This->stateBlock) {
2248 IWineD3DStateBlock_Release((IWineD3DStateBlock *) This->stateBlock);
2249 This->stateBlock = NULL;
2251 if (This->blit_priv) {
2252 This->blitter->free_private(iface);
2254 if (This->fragment_priv) {
2255 This->frag_pipe->free_private(iface);
2257 if (This->shader_priv) {
2258 This->shader_backend->shader_free_private(iface);
2260 return hr;
2263 static HRESULT WINAPI IWineD3DDeviceImpl_InitGDI(IWineD3DDevice *iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters, D3DCB_CREATEADDITIONALSWAPCHAIN D3DCB_CreateAdditionalSwapChain) {
2264 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2265 IWineD3DSwapChainImpl *swapchain = NULL;
2266 HRESULT hr;
2268 /* Setup the implicit swapchain */
2269 TRACE("Creating implicit swapchain\n");
2270 hr=D3DCB_CreateAdditionalSwapChain(This->parent, pPresentationParameters, (IWineD3DSwapChain **)&swapchain);
2271 if (FAILED(hr) || !swapchain) {
2272 WARN("Failed to create implicit swapchain\n");
2273 goto err_out;
2276 This->NumberOfSwapChains = 1;
2277 This->swapchains = HeapAlloc(GetProcessHeap(), 0, This->NumberOfSwapChains * sizeof(IWineD3DSwapChain *));
2278 if(!This->swapchains) {
2279 ERR("Out of memory!\n");
2280 goto err_out;
2282 This->swapchains[0] = (IWineD3DSwapChain *) swapchain;
2283 return WINED3D_OK;
2285 err_out:
2286 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
2287 return hr;
2290 static HRESULT WINAPI IWineD3DDeviceImpl_Uninit3D(IWineD3DDevice *iface, D3DCB_DESTROYSURFACEFN D3DCB_DestroyDepthStencilSurface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2291 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2292 int sampler;
2293 UINT i;
2294 TRACE("(%p)\n", This);
2296 if(!This->d3d_initialized) return WINED3DERR_INVALIDCALL;
2298 /* I don't think that the interface guarantees that the device is destroyed from the same thread
2299 * it was created. Thus make sure a context is active for the glDelete* calls
2301 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
2303 if(This->logo_surface) IWineD3DSurface_Release(This->logo_surface);
2305 TRACE("Deleting high order patches\n");
2306 for(i = 0; i < PATCHMAP_SIZE; i++) {
2307 struct list *e1, *e2;
2308 struct WineD3DRectPatch *patch;
2309 LIST_FOR_EACH_SAFE(e1, e2, &This->patches[i]) {
2310 patch = LIST_ENTRY(e1, struct WineD3DRectPatch, entry);
2311 IWineD3DDevice_DeletePatch(iface, patch->Handle);
2315 /* Delete the palette conversion shader if it is around */
2316 if(This->paletteConversionShader) {
2317 ENTER_GL();
2318 GL_EXTCALL(glDeleteProgramsARB(1, &This->paletteConversionShader));
2319 LEAVE_GL();
2320 This->paletteConversionShader = 0;
2323 /* Delete the pbuffer context if there is any */
2324 if(This->pbufferContext) DestroyContext(This, This->pbufferContext);
2326 /* Delete the mouse cursor texture */
2327 if(This->cursorTexture) {
2328 ENTER_GL();
2329 glDeleteTextures(1, &This->cursorTexture);
2330 LEAVE_GL();
2331 This->cursorTexture = 0;
2334 for (sampler = 0; sampler < MAX_FRAGMENT_SAMPLERS; ++sampler) {
2335 IWineD3DDevice_SetTexture(iface, sampler, NULL);
2337 for (sampler = 0; sampler < MAX_VERTEX_SAMPLERS; ++sampler) {
2338 IWineD3DDevice_SetTexture(iface, WINED3DVERTEXTEXTURESAMPLER0 + sampler, NULL);
2341 /* Destroy the depth blt resources, they will be invalid after the reset. Also free shader
2342 * private data, it might contain opengl pointers
2344 if(This->depth_blt_texture) {
2345 glDeleteTextures(1, &This->depth_blt_texture);
2346 This->depth_blt_texture = 0;
2348 if (This->depth_blt_rb) {
2349 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
2350 This->depth_blt_rb = 0;
2351 This->depth_blt_rb_w = 0;
2352 This->depth_blt_rb_h = 0;
2355 /* Release the update stateblock */
2356 if(IWineD3DStateBlock_Release((IWineD3DStateBlock *)This->updateStateBlock) > 0){
2357 if(This->updateStateBlock != This->stateBlock)
2358 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2360 This->updateStateBlock = NULL;
2362 { /* because were not doing proper internal refcounts releasing the primary state block
2363 causes recursion with the extra checks in ResourceReleased, to avoid this we have
2364 to set this->stateBlock = NULL; first */
2365 IWineD3DStateBlock *stateBlock = (IWineD3DStateBlock *)This->stateBlock;
2366 This->stateBlock = NULL;
2368 /* Release the stateblock */
2369 if(IWineD3DStateBlock_Release(stateBlock) > 0){
2370 FIXME("(%p) Something's still holding the Update stateblock\n",This);
2374 /* Destroy the shader backend. Note that this has to happen after all shaders are destroyed. */
2375 This->blitter->free_private(iface);
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->draw_buffers);
2419 This->render_targets = NULL;
2420 This->draw_buffers = NULL;
2422 This->d3d_initialized = FALSE;
2423 return WINED3D_OK;
2426 static HRESULT WINAPI IWineD3DDeviceImpl_UninitGDI(IWineD3DDevice *iface, D3DCB_DESTROYSWAPCHAINFN D3DCB_DestroySwapChain) {
2427 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2428 unsigned int i;
2430 for(i=0; i < This->NumberOfSwapChains; i++) {
2431 TRACE("Releasing the implicit swapchain %d\n", i);
2432 if (D3DCB_DestroySwapChain(This->swapchains[i]) > 0) {
2433 FIXME("(%p) Something's still holding the implicit swapchain\n", This);
2437 HeapFree(GetProcessHeap(), 0, This->swapchains);
2438 This->swapchains = NULL;
2439 This->NumberOfSwapChains = 0;
2440 return WINED3D_OK;
2443 /* Enables thread safety in the wined3d device and its resources. Called by DirectDraw
2444 * from SetCooperativeLevel if DDSCL_MULTITHREADED is specified, and by d3d8/9 from
2445 * CreateDevice if D3DCREATE_MULTITHREADED is passed.
2447 * There is no way to deactivate thread safety once it is enabled.
2449 static void WINAPI IWineD3DDeviceImpl_SetMultithreaded(IWineD3DDevice *iface) {
2450 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
2452 /*For now just store the flag(needed in case of ddraw) */
2453 This->createParms.BehaviorFlags |= WINED3DCREATE_MULTITHREADED;
2455 return;
2458 static HRESULT WINAPI IWineD3DDeviceImpl_SetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
2459 DEVMODEW devmode;
2460 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2461 LONG ret;
2462 const StaticPixelFormatDesc *formatDesc = getFormatDescEntry(pMode->Format, NULL, NULL);
2463 RECT clip_rc;
2465 TRACE("(%p)->(%d,%p) Mode=%dx%dx@%d, %s\n", This, iSwapChain, pMode, pMode->Width, pMode->Height, pMode->RefreshRate, debug_d3dformat(pMode->Format));
2467 /* Resize the screen even without a window:
2468 * The app could have unset it with SetCooperativeLevel, but not called
2469 * RestoreDisplayMode first. Then the release will call RestoreDisplayMode,
2470 * but we don't have any hwnd
2473 memset(&devmode, 0, sizeof(devmode));
2474 devmode.dmSize = sizeof(devmode);
2475 devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
2476 devmode.dmBitsPerPel = formatDesc->bpp * 8;
2477 devmode.dmPelsWidth = pMode->Width;
2478 devmode.dmPelsHeight = pMode->Height;
2480 devmode.dmDisplayFrequency = pMode->RefreshRate;
2481 if (pMode->RefreshRate != 0) {
2482 devmode.dmFields |= DM_DISPLAYFREQUENCY;
2485 /* Only change the mode if necessary */
2486 if( (This->ddraw_width == pMode->Width) &&
2487 (This->ddraw_height == pMode->Height) &&
2488 (This->ddraw_format == pMode->Format) &&
2489 (pMode->RefreshRate == 0) ) {
2490 return WINED3D_OK;
2493 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL);
2494 if (ret != DISP_CHANGE_SUCCESSFUL) {
2495 if(devmode.dmDisplayFrequency != 0) {
2496 WARN("ChangeDisplaySettingsExW failed, trying without the refresh rate\n");
2497 devmode.dmFields &= ~DM_DISPLAYFREQUENCY;
2498 devmode.dmDisplayFrequency = 0;
2499 ret = ChangeDisplaySettingsExW(NULL, &devmode, NULL, CDS_FULLSCREEN, NULL) != DISP_CHANGE_SUCCESSFUL;
2501 if(ret != DISP_CHANGE_SUCCESSFUL) {
2502 return WINED3DERR_NOTAVAILABLE;
2506 /* Store the new values */
2507 This->ddraw_width = pMode->Width;
2508 This->ddraw_height = pMode->Height;
2509 This->ddraw_format = pMode->Format;
2511 /* And finally clip mouse to our screen */
2512 SetRect(&clip_rc, 0, 0, pMode->Width, pMode->Height);
2513 ClipCursor(&clip_rc);
2515 return WINED3D_OK;
2518 static HRESULT WINAPI IWineD3DDeviceImpl_GetDirect3D(IWineD3DDevice *iface, IWineD3D **ppD3D) {
2519 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2520 *ppD3D= This->wineD3D;
2521 TRACE("(%p) : wineD3D returning %p\n", This, *ppD3D);
2522 IWineD3D_AddRef(*ppD3D);
2523 return WINED3D_OK;
2526 static UINT WINAPI IWineD3DDeviceImpl_GetAvailableTextureMem(IWineD3DDevice *iface) {
2527 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2529 TRACE("(%p) : simulating %dMB, returning %dMB left\n", This,
2530 (This->adapter->TextureRam/(1024*1024)),
2531 ((This->adapter->TextureRam - This->adapter->UsedTextureRam) / (1024*1024)));
2532 /* return simulated texture memory left */
2533 return (This->adapter->TextureRam - This->adapter->UsedTextureRam);
2538 /*****
2539 * Get / Set FVF
2540 *****/
2541 static HRESULT WINAPI IWineD3DDeviceImpl_SetFVF(IWineD3DDevice *iface, DWORD fvf) {
2542 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2544 /* Update the current state block */
2545 This->updateStateBlock->changed.fvf = TRUE;
2547 if(This->updateStateBlock->fvf == fvf) {
2548 TRACE("Application is setting the old fvf over, nothing to do\n");
2549 return WINED3D_OK;
2552 This->updateStateBlock->fvf = fvf;
2553 TRACE("(%p) : FVF Shader FVF set to %x\n", This, fvf);
2554 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
2555 return WINED3D_OK;
2559 static HRESULT WINAPI IWineD3DDeviceImpl_GetFVF(IWineD3DDevice *iface, DWORD *pfvf) {
2560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2561 TRACE("(%p) : GetFVF returning %x\n", This, This->stateBlock->fvf);
2562 *pfvf = This->stateBlock->fvf;
2563 return WINED3D_OK;
2566 /*****
2567 * Get / Set Stream Source
2568 *****/
2569 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer* pStreamData, UINT OffsetInBytes, UINT Stride) {
2570 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2571 IWineD3DVertexBuffer *oldSrc;
2573 if (StreamNumber >= MAX_STREAMS) {
2574 WARN("Stream out of range %d\n", StreamNumber);
2575 return WINED3DERR_INVALIDCALL;
2576 } else if(OffsetInBytes & 0x3) {
2577 WARN("OffsetInBytes is not 4 byte aligned: %d\n", OffsetInBytes);
2578 return WINED3DERR_INVALIDCALL;
2581 oldSrc = This->updateStateBlock->streamSource[StreamNumber];
2582 TRACE("(%p) : StreamNo: %u, OldStream (%p), NewStream (%p), OffsetInBytes %u, NewStride %u\n", This, StreamNumber, oldSrc, pStreamData, OffsetInBytes, Stride);
2584 This->updateStateBlock->changed.streamSource[StreamNumber] = TRUE;
2586 if(oldSrc == pStreamData &&
2587 This->updateStateBlock->streamStride[StreamNumber] == Stride &&
2588 This->updateStateBlock->streamOffset[StreamNumber] == OffsetInBytes) {
2589 TRACE("Application is setting the old values over, nothing to do\n");
2590 return WINED3D_OK;
2593 This->updateStateBlock->streamSource[StreamNumber] = pStreamData;
2594 if (pStreamData) {
2595 This->updateStateBlock->streamStride[StreamNumber] = Stride;
2596 This->updateStateBlock->streamOffset[StreamNumber] = OffsetInBytes;
2599 /* Handle recording of state blocks */
2600 if (This->isRecordingState) {
2601 TRACE("Recording... not performing anything\n");
2602 if(pStreamData) IWineD3DVertexBuffer_AddRef(pStreamData);
2603 if(oldSrc) IWineD3DVertexBuffer_Release(oldSrc);
2604 return WINED3D_OK;
2607 /* Need to do a getParent and pass the references up */
2608 /* MSDN says ..... When an application no longer holds a reference to this interface, the interface will automatically be freed.
2609 which suggests that we shouldn't be ref counting? and do need a _release on the stream source to reset the stream source
2610 so for now, just count internally */
2611 if (pStreamData != NULL) {
2612 IWineD3DVertexBufferImpl *vbImpl = (IWineD3DVertexBufferImpl *) pStreamData;
2613 InterlockedIncrement(&vbImpl->bindCount);
2614 IWineD3DVertexBuffer_AddRef(pStreamData);
2616 if (oldSrc != NULL) {
2617 InterlockedDecrement(&((IWineD3DVertexBufferImpl *) oldSrc)->bindCount);
2618 IWineD3DVertexBuffer_Release(oldSrc);
2621 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2623 return WINED3D_OK;
2626 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSource(IWineD3DDevice *iface, UINT StreamNumber,IWineD3DVertexBuffer** pStream, UINT *pOffset, UINT* pStride) {
2627 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2629 TRACE("(%p) : StreamNo: %u, Stream (%p), Offset %u, Stride %u\n", This, StreamNumber,
2630 This->stateBlock->streamSource[StreamNumber],
2631 This->stateBlock->streamOffset[StreamNumber],
2632 This->stateBlock->streamStride[StreamNumber]);
2634 if (StreamNumber >= MAX_STREAMS) {
2635 WARN("Stream out of range %d\n", StreamNumber);
2636 return WINED3DERR_INVALIDCALL;
2638 *pStream = This->stateBlock->streamSource[StreamNumber];
2639 *pStride = This->stateBlock->streamStride[StreamNumber];
2640 if (pOffset) {
2641 *pOffset = This->stateBlock->streamOffset[StreamNumber];
2644 if (*pStream != NULL) {
2645 IWineD3DVertexBuffer_AddRef(*pStream); /* We have created a new reference to the VB */
2647 return WINED3D_OK;
2650 static HRESULT WINAPI IWineD3DDeviceImpl_SetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT Divider) {
2651 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2652 UINT oldFlags = This->updateStateBlock->streamFlags[StreamNumber];
2653 UINT oldFreq = This->updateStateBlock->streamFreq[StreamNumber];
2655 /* Verify input at least in d3d9 this is invalid*/
2656 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && (Divider & WINED3DSTREAMSOURCE_INDEXEDDATA)){
2657 WARN("INSTANCEDATA and INDEXEDDATA were set, returning D3DERR_INVALIDCALL\n");
2658 return WINED3DERR_INVALIDCALL;
2660 if( (Divider & WINED3DSTREAMSOURCE_INSTANCEDATA) && StreamNumber == 0 ){
2661 WARN("INSTANCEDATA used on stream 0, returning D3DERR_INVALIDCALL\n");
2662 return WINED3DERR_INVALIDCALL;
2664 if( Divider == 0 ){
2665 WARN("Divider is 0, returning D3DERR_INVALIDCALL\n");
2666 return WINED3DERR_INVALIDCALL;
2669 TRACE("(%p) StreamNumber(%d), Divider(%d)\n", This, StreamNumber, Divider);
2670 This->updateStateBlock->streamFlags[StreamNumber] = Divider & (WINED3DSTREAMSOURCE_INSTANCEDATA | WINED3DSTREAMSOURCE_INDEXEDDATA );
2672 This->updateStateBlock->changed.streamFreq[StreamNumber] = TRUE;
2673 This->updateStateBlock->streamFreq[StreamNumber] = Divider & 0x7FFFFF;
2675 if(This->updateStateBlock->streamFreq[StreamNumber] != oldFreq ||
2676 This->updateStateBlock->streamFlags[StreamNumber] != oldFlags) {
2677 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
2680 return WINED3D_OK;
2683 static HRESULT WINAPI IWineD3DDeviceImpl_GetStreamSourceFreq(IWineD3DDevice *iface, UINT StreamNumber, UINT* Divider) {
2684 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2686 TRACE("(%p) StreamNumber(%d), Divider(%p)\n", This, StreamNumber, Divider);
2687 *Divider = This->updateStateBlock->streamFreq[StreamNumber] | This->updateStateBlock->streamFlags[StreamNumber];
2689 TRACE("(%p) : returning %d\n", This, *Divider);
2691 return WINED3D_OK;
2694 /*****
2695 * Get / Set & Multiply Transform
2696 *****/
2697 static HRESULT WINAPI IWineD3DDeviceImpl_SetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE d3dts, CONST WINED3DMATRIX* lpmatrix) {
2698 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2700 /* Most of this routine, comments included copied from ddraw tree initially: */
2701 TRACE("(%p) : Transform State=%s\n", This, debug_d3dtstype(d3dts));
2703 /* Handle recording of state blocks */
2704 if (This->isRecordingState) {
2705 TRACE("Recording... not performing anything\n");
2706 This->updateStateBlock->changed.transform[d3dts] = TRUE;
2707 This->updateStateBlock->transforms[d3dts] = *lpmatrix;
2708 return WINED3D_OK;
2712 * If the new matrix is the same as the current one,
2713 * we cut off any further processing. this seems to be a reasonable
2714 * optimization because as was noticed, some apps (warcraft3 for example)
2715 * tend towards setting the same matrix repeatedly for some reason.
2717 * From here on we assume that the new matrix is different, wherever it matters.
2719 if (!memcmp(&This->stateBlock->transforms[d3dts].u.m[0][0], lpmatrix, sizeof(WINED3DMATRIX))) {
2720 TRACE("The app is setting the same matrix over again\n");
2721 return WINED3D_OK;
2722 } else {
2723 conv_mat(lpmatrix, &This->stateBlock->transforms[d3dts].u.m[0][0]);
2727 ScreenCoord = ProjectionMat * ViewMat * WorldMat * ObjectCoord
2728 where ViewMat = Camera space, WorldMat = world space.
2730 In OpenGL, camera and world space is combined into GL_MODELVIEW
2731 matrix. The Projection matrix stay projection matrix.
2734 /* Capture the times we can just ignore the change for now */
2735 if (d3dts == WINED3DTS_VIEW) { /* handle the VIEW matrix */
2736 This->view_ident = !memcmp(lpmatrix, identity, 16 * sizeof(float));
2737 /* Handled by the state manager */
2740 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TRANSFORM(d3dts));
2741 return WINED3D_OK;
2744 static HRESULT WINAPI IWineD3DDeviceImpl_GetTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, WINED3DMATRIX* pMatrix) {
2745 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2746 TRACE("(%p) : for Transform State %s\n", This, debug_d3dtstype(State));
2747 *pMatrix = This->stateBlock->transforms[State];
2748 return WINED3D_OK;
2751 static HRESULT WINAPI IWineD3DDeviceImpl_MultiplyTransform(IWineD3DDevice *iface, WINED3DTRANSFORMSTATETYPE State, CONST WINED3DMATRIX* pMatrix) {
2752 WINED3DMATRIX *mat = NULL;
2753 WINED3DMATRIX temp;
2755 /* Note: Using 'updateStateBlock' rather than 'stateblock' in the code
2756 * below means it will be recorded in a state block change, but it
2757 * works regardless where it is recorded.
2758 * If this is found to be wrong, change to StateBlock.
2760 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2761 TRACE("(%p) : For state %s\n", This, debug_d3dtstype(State));
2763 if (State < HIGHEST_TRANSFORMSTATE)
2765 mat = &This->updateStateBlock->transforms[State];
2766 } else {
2767 FIXME("Unhandled transform state!!\n");
2770 multiply_matrix(&temp, mat, pMatrix);
2772 /* Apply change via set transform - will reapply to eg. lights this way */
2773 return IWineD3DDeviceImpl_SetTransform(iface, State, &temp);
2776 /*****
2777 * Get / Set Light
2778 *****/
2779 /* Note lights are real special cases. Although the device caps state only eg. 8 are supported,
2780 you can reference any indexes you want as long as that number max are enabled at any
2781 one point in time! Therefore since the indexes can be anything, we need a hashmap of them.
2782 However, this causes stateblock problems. When capturing the state block, I duplicate the hashmap,
2783 but when recording, just build a chain pretty much of commands to be replayed. */
2785 static HRESULT WINAPI IWineD3DDeviceImpl_SetLight(IWineD3DDevice *iface, DWORD Index, CONST WINED3DLIGHT* pLight) {
2786 float rho;
2787 PLIGHTINFOEL *object = NULL;
2788 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2789 struct list *e;
2791 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2792 TRACE("(%p) : Idx(%d), pLight(%p). Hash index is %d\n", This, Index, pLight, Hi);
2794 /* Check the parameter range. Need for speed most wanted sets junk lights which confuse
2795 * the gl driver.
2797 if(!pLight) {
2798 WARN("Light pointer = NULL, returning WINED3DERR_INVALIDCALL\n");
2799 return WINED3DERR_INVALIDCALL;
2802 switch(pLight->Type) {
2803 case WINED3DLIGHT_POINT:
2804 case WINED3DLIGHT_SPOT:
2805 case WINED3DLIGHT_PARALLELPOINT:
2806 case WINED3DLIGHT_GLSPOT:
2807 /* Incorrect attenuation values can cause the gl driver to crash. Happens with Need for speed
2808 * most wanted
2810 if(pLight->Attenuation0 < 0.0 || pLight->Attenuation1 < 0.0 || pLight->Attenuation2 < 0.0) {
2811 WARN("Attenuation is negative, returning WINED3DERR_INVALIDCALL\n");
2812 return WINED3DERR_INVALIDCALL;
2814 break;
2816 case WINED3DLIGHT_DIRECTIONAL:
2817 /* Ignores attenuation */
2818 break;
2820 default:
2821 WARN("Light type out of range, returning WINED3DERR_INVALIDCALL\n");
2822 return WINED3DERR_INVALIDCALL;
2825 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2826 object = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2827 if(object->OriginalIndex == Index) break;
2828 object = NULL;
2831 if(!object) {
2832 TRACE("Adding new light\n");
2833 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
2834 if(!object) {
2835 ERR("Out of memory error when allocating a light\n");
2836 return E_OUTOFMEMORY;
2838 list_add_head(&This->updateStateBlock->lightMap[Hi], &object->entry);
2839 object->glIndex = -1;
2840 object->OriginalIndex = Index;
2841 object->changed = TRUE;
2844 /* Initialize the object */
2845 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,
2846 pLight->Diffuse.r, pLight->Diffuse.g, pLight->Diffuse.b, pLight->Diffuse.a,
2847 pLight->Specular.r, pLight->Specular.g, pLight->Specular.b, pLight->Specular.a,
2848 pLight->Ambient.r, pLight->Ambient.g, pLight->Ambient.b, pLight->Ambient.a);
2849 TRACE("... Pos(%f,%f,%f), Dirn(%f,%f,%f)\n", pLight->Position.x, pLight->Position.y, pLight->Position.z,
2850 pLight->Direction.x, pLight->Direction.y, pLight->Direction.z);
2851 TRACE("... Range(%f), Falloff(%f), Theta(%f), Phi(%f)\n", pLight->Range, pLight->Falloff, pLight->Theta, pLight->Phi);
2853 /* Save away the information */
2854 object->OriginalParms = *pLight;
2856 switch (pLight->Type) {
2857 case WINED3DLIGHT_POINT:
2858 /* Position */
2859 object->lightPosn[0] = pLight->Position.x;
2860 object->lightPosn[1] = pLight->Position.y;
2861 object->lightPosn[2] = pLight->Position.z;
2862 object->lightPosn[3] = 1.0f;
2863 object->cutoff = 180.0f;
2864 /* FIXME: Range */
2865 break;
2867 case WINED3DLIGHT_DIRECTIONAL:
2868 /* Direction */
2869 object->lightPosn[0] = -pLight->Direction.x;
2870 object->lightPosn[1] = -pLight->Direction.y;
2871 object->lightPosn[2] = -pLight->Direction.z;
2872 object->lightPosn[3] = 0.0;
2873 object->exponent = 0.0f;
2874 object->cutoff = 180.0f;
2875 break;
2877 case WINED3DLIGHT_SPOT:
2878 /* Position */
2879 object->lightPosn[0] = pLight->Position.x;
2880 object->lightPosn[1] = pLight->Position.y;
2881 object->lightPosn[2] = pLight->Position.z;
2882 object->lightPosn[3] = 1.0;
2884 /* Direction */
2885 object->lightDirn[0] = pLight->Direction.x;
2886 object->lightDirn[1] = pLight->Direction.y;
2887 object->lightDirn[2] = pLight->Direction.z;
2888 object->lightDirn[3] = 1.0;
2891 * opengl-ish and d3d-ish spot lights use too different models for the
2892 * light "intensity" as a function of the angle towards the main light direction,
2893 * so we only can approximate very roughly.
2894 * however spot lights are rather rarely used in games (if ever used at all).
2895 * furthermore if still used, probably nobody pays attention to such details.
2897 if (pLight->Falloff == 0) {
2898 /* Falloff = 0 is easy, because d3d's and opengl's spot light equations have the
2899 * falloff resp. exponent parameter as an exponent, so the spot light lighting
2900 * will always be 1.0 for both of them, and we don't have to care for the
2901 * rest of the rather complex calculation
2903 object->exponent = 0;
2904 } else {
2905 rho = pLight->Theta + (pLight->Phi - pLight->Theta)/(2*pLight->Falloff);
2906 if (rho < 0.0001) rho = 0.0001f;
2907 object->exponent = -0.3/log(cos(rho/2));
2909 if (object->exponent > 128.0) {
2910 object->exponent = 128.0;
2912 object->cutoff = pLight->Phi*90/M_PI;
2914 /* FIXME: Range */
2915 break;
2917 default:
2918 FIXME("Unrecognized light type %d\n", pLight->Type);
2921 /* Update the live definitions if the light is currently assigned a glIndex */
2922 if (object->glIndex != -1 && !This->isRecordingState) {
2923 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(object->glIndex));
2925 return WINED3D_OK;
2928 static HRESULT WINAPI IWineD3DDeviceImpl_GetLight(IWineD3DDevice *iface, DWORD Index, WINED3DLIGHT* pLight) {
2929 PLIGHTINFOEL *lightInfo = NULL;
2930 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2931 DWORD Hi = LIGHTMAP_HASHFUNC(Index);
2932 struct list *e;
2933 TRACE("(%p) : Idx(%d), pLight(%p)\n", This, Index, pLight);
2935 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
2936 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2937 if(lightInfo->OriginalIndex == Index) break;
2938 lightInfo = NULL;
2941 if (lightInfo == NULL) {
2942 TRACE("Light information requested but light not defined\n");
2943 return WINED3DERR_INVALIDCALL;
2946 *pLight = lightInfo->OriginalParms;
2947 return WINED3D_OK;
2950 /*****
2951 * Get / Set Light Enable
2952 * (Note for consistency, renamed d3dx function by adding the 'set' prefix)
2953 *****/
2954 static HRESULT WINAPI IWineD3DDeviceImpl_SetLightEnable(IWineD3DDevice *iface, DWORD Index, BOOL Enable) {
2955 PLIGHTINFOEL *lightInfo = NULL;
2956 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
2957 UINT Hi = LIGHTMAP_HASHFUNC(Index);
2958 struct list *e;
2959 TRACE("(%p) : Idx(%d), enable? %d\n", This, Index, Enable);
2961 /* Tests show true = 128...not clear why */
2962 Enable = Enable? 128: 0;
2964 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2965 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2966 if(lightInfo->OriginalIndex == Index) break;
2967 lightInfo = NULL;
2969 TRACE("Found light: %p\n", lightInfo);
2971 /* Special case - enabling an undefined light creates one with a strict set of parms! */
2972 if (lightInfo == NULL) {
2974 TRACE("Light enabled requested but light not defined, so defining one!\n");
2975 IWineD3DDeviceImpl_SetLight(iface, Index, &WINED3D_default_light);
2977 /* Search for it again! Should be fairly quick as near head of list */
2978 LIST_FOR_EACH(e, &This->updateStateBlock->lightMap[Hi]) {
2979 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
2980 if(lightInfo->OriginalIndex == Index) break;
2981 lightInfo = NULL;
2983 if (lightInfo == NULL) {
2984 FIXME("Adding default lights has failed dismally\n");
2985 return WINED3DERR_INVALIDCALL;
2989 lightInfo->enabledChanged = TRUE;
2990 if(!Enable) {
2991 if(lightInfo->glIndex != -1) {
2992 if(!This->isRecordingState) {
2993 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(lightInfo->glIndex));
2996 This->stateBlock->activeLights[lightInfo->glIndex] = NULL;
2997 lightInfo->glIndex = -1;
2998 } else {
2999 TRACE("Light already disabled, nothing to do\n");
3001 lightInfo->enabled = FALSE;
3002 } else {
3003 lightInfo->enabled = TRUE;
3004 if (lightInfo->glIndex != -1) {
3005 /* nop */
3006 TRACE("Nothing to do as light was enabled\n");
3007 } else {
3008 int i;
3009 /* Find a free gl light */
3010 for(i = 0; i < This->maxConcurrentLights; i++) {
3011 if(This->stateBlock->activeLights[i] == NULL) {
3012 This->stateBlock->activeLights[i] = lightInfo;
3013 lightInfo->glIndex = i;
3014 break;
3017 if(lightInfo->glIndex == -1) {
3018 /* Our tests show that Windows returns D3D_OK in this situation, even with
3019 * D3DCREATE_HARDWARE_VERTEXPROCESSING | D3DCREATE_PUREDEVICE devices. This
3020 * is consistent among ddraw, d3d8 and d3d9. GetLightEnable returns TRUE
3021 * as well for those lights.
3023 * TODO: Test how this affects rendering
3025 FIXME("Too many concurrently active lights\n");
3026 return WINED3D_OK;
3029 /* i == lightInfo->glIndex */
3030 if(!This->isRecordingState) {
3031 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_ACTIVELIGHT(i));
3036 return WINED3D_OK;
3039 static HRESULT WINAPI IWineD3DDeviceImpl_GetLightEnable(IWineD3DDevice *iface, DWORD Index,BOOL* pEnable) {
3041 PLIGHTINFOEL *lightInfo = NULL;
3042 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3043 struct list *e;
3044 UINT Hi = LIGHTMAP_HASHFUNC(Index);
3045 TRACE("(%p) : for idx(%d)\n", This, Index);
3047 LIST_FOR_EACH(e, &This->stateBlock->lightMap[Hi]) {
3048 lightInfo = LIST_ENTRY(e, PLIGHTINFOEL, entry);
3049 if(lightInfo->OriginalIndex == Index) break;
3050 lightInfo = NULL;
3053 if (lightInfo == NULL) {
3054 TRACE("Light enabled state requested but light not defined\n");
3055 return WINED3DERR_INVALIDCALL;
3057 /* true is 128 according to SetLightEnable */
3058 *pEnable = lightInfo->enabled ? 128 : 0;
3059 return WINED3D_OK;
3062 /*****
3063 * Get / Set Clip Planes
3064 *****/
3065 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipPlane(IWineD3DDevice *iface, DWORD Index, CONST float *pPlane) {
3066 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3067 TRACE("(%p) : for idx %d, %p\n", This, Index, pPlane);
3069 /* Validate Index */
3070 if (Index >= GL_LIMITS(clipplanes)) {
3071 TRACE("Application has requested clipplane this device doesn't support\n");
3072 return WINED3DERR_INVALIDCALL;
3075 This->updateStateBlock->changed.clipplane[Index] = TRUE;
3077 if(This->updateStateBlock->clipplane[Index][0] == pPlane[0] &&
3078 This->updateStateBlock->clipplane[Index][1] == pPlane[1] &&
3079 This->updateStateBlock->clipplane[Index][2] == pPlane[2] &&
3080 This->updateStateBlock->clipplane[Index][3] == pPlane[3]) {
3081 TRACE("Application is setting old values over, nothing to do\n");
3082 return WINED3D_OK;
3085 This->updateStateBlock->clipplane[Index][0] = pPlane[0];
3086 This->updateStateBlock->clipplane[Index][1] = pPlane[1];
3087 This->updateStateBlock->clipplane[Index][2] = pPlane[2];
3088 This->updateStateBlock->clipplane[Index][3] = pPlane[3];
3090 /* Handle recording of state blocks */
3091 if (This->isRecordingState) {
3092 TRACE("Recording... not performing anything\n");
3093 return WINED3D_OK;
3096 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_CLIPPLANE(Index));
3098 return WINED3D_OK;
3101 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipPlane(IWineD3DDevice *iface, DWORD Index, float *pPlane) {
3102 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3103 TRACE("(%p) : for idx %d\n", This, Index);
3105 /* Validate Index */
3106 if (Index >= GL_LIMITS(clipplanes)) {
3107 TRACE("Application has requested clipplane this device doesn't support\n");
3108 return WINED3DERR_INVALIDCALL;
3111 pPlane[0] = This->stateBlock->clipplane[Index][0];
3112 pPlane[1] = This->stateBlock->clipplane[Index][1];
3113 pPlane[2] = This->stateBlock->clipplane[Index][2];
3114 pPlane[3] = This->stateBlock->clipplane[Index][3];
3115 return WINED3D_OK;
3118 /*****
3119 * Get / Set Clip Plane Status
3120 * WARNING: This code relies on the fact that D3DCLIPSTATUS8 == D3DCLIPSTATUS9
3121 *****/
3122 static HRESULT WINAPI IWineD3DDeviceImpl_SetClipStatus(IWineD3DDevice *iface, CONST WINED3DCLIPSTATUS* pClipStatus) {
3123 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3124 FIXME("(%p) : stub\n", This);
3125 if (NULL == pClipStatus) {
3126 return WINED3DERR_INVALIDCALL;
3128 This->updateStateBlock->clip_status.ClipUnion = pClipStatus->ClipUnion;
3129 This->updateStateBlock->clip_status.ClipIntersection = pClipStatus->ClipIntersection;
3130 return WINED3D_OK;
3133 static HRESULT WINAPI IWineD3DDeviceImpl_GetClipStatus(IWineD3DDevice *iface, WINED3DCLIPSTATUS* pClipStatus) {
3134 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3135 FIXME("(%p) : stub\n", This);
3136 if (NULL == pClipStatus) {
3137 return WINED3DERR_INVALIDCALL;
3139 pClipStatus->ClipUnion = This->updateStateBlock->clip_status.ClipUnion;
3140 pClipStatus->ClipIntersection = This->updateStateBlock->clip_status.ClipIntersection;
3141 return WINED3D_OK;
3144 /*****
3145 * Get / Set Material
3146 *****/
3147 static HRESULT WINAPI IWineD3DDeviceImpl_SetMaterial(IWineD3DDevice *iface, CONST WINED3DMATERIAL* pMaterial) {
3148 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3150 This->updateStateBlock->changed.material = TRUE;
3151 This->updateStateBlock->material = *pMaterial;
3153 /* Handle recording of state blocks */
3154 if (This->isRecordingState) {
3155 TRACE("Recording... not performing anything\n");
3156 return WINED3D_OK;
3159 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_MATERIAL);
3160 return WINED3D_OK;
3163 static HRESULT WINAPI IWineD3DDeviceImpl_GetMaterial(IWineD3DDevice *iface, WINED3DMATERIAL* pMaterial) {
3164 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3165 *pMaterial = This->updateStateBlock->material;
3166 TRACE("(%p) : Diffuse (%f,%f,%f,%f)\n", This, pMaterial->Diffuse.r, pMaterial->Diffuse.g,
3167 pMaterial->Diffuse.b, pMaterial->Diffuse.a);
3168 TRACE("(%p) : Ambient (%f,%f,%f,%f)\n", This, pMaterial->Ambient.r, pMaterial->Ambient.g,
3169 pMaterial->Ambient.b, pMaterial->Ambient.a);
3170 TRACE("(%p) : Specular (%f,%f,%f,%f)\n", This, pMaterial->Specular.r, pMaterial->Specular.g,
3171 pMaterial->Specular.b, pMaterial->Specular.a);
3172 TRACE("(%p) : Emissive (%f,%f,%f,%f)\n", This, pMaterial->Emissive.r, pMaterial->Emissive.g,
3173 pMaterial->Emissive.b, pMaterial->Emissive.a);
3174 TRACE("(%p) : Power (%f)\n", This, pMaterial->Power);
3176 return WINED3D_OK;
3179 /*****
3180 * Get / Set Indices
3181 *****/
3182 static HRESULT WINAPI IWineD3DDeviceImpl_SetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer* pIndexData) {
3183 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3184 IWineD3DIndexBuffer *oldIdxs;
3186 TRACE("(%p) : Setting to %p\n", This, pIndexData);
3187 oldIdxs = This->updateStateBlock->pIndexData;
3189 This->updateStateBlock->changed.indices = TRUE;
3190 This->updateStateBlock->pIndexData = pIndexData;
3192 /* Handle recording of state blocks */
3193 if (This->isRecordingState) {
3194 TRACE("Recording... not performing anything\n");
3195 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3196 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3197 return WINED3D_OK;
3200 if(oldIdxs != pIndexData) {
3201 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
3202 if(pIndexData) IWineD3DIndexBuffer_AddRef(pIndexData);
3203 if(oldIdxs) IWineD3DIndexBuffer_Release(oldIdxs);
3205 return WINED3D_OK;
3208 static HRESULT WINAPI IWineD3DDeviceImpl_GetIndices(IWineD3DDevice *iface, IWineD3DIndexBuffer** ppIndexData) {
3209 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3211 *ppIndexData = This->stateBlock->pIndexData;
3213 /* up ref count on ppindexdata */
3214 if (*ppIndexData) {
3215 IWineD3DIndexBuffer_AddRef(*ppIndexData);
3216 TRACE("(%p) index data set to %p\n", This, ppIndexData);
3217 }else{
3218 TRACE("(%p) No index data set\n", This);
3220 TRACE("Returning %p\n", *ppIndexData);
3222 return WINED3D_OK;
3225 /* Method to offer d3d9 a simple way to set the base vertex index without messing with the index buffer */
3226 static HRESULT WINAPI IWineD3DDeviceImpl_SetBaseVertexIndex(IWineD3DDevice *iface, INT BaseIndex) {
3227 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3228 TRACE("(%p)->(%d)\n", This, BaseIndex);
3230 if(This->updateStateBlock->baseVertexIndex == BaseIndex) {
3231 TRACE("Application is setting the old value over, nothing to do\n");
3232 return WINED3D_OK;
3235 This->updateStateBlock->baseVertexIndex = BaseIndex;
3237 if (This->isRecordingState) {
3238 TRACE("Recording... not performing anything\n");
3239 return WINED3D_OK;
3241 /* The base vertex index affects the stream sources */
3242 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
3243 return WINED3D_OK;
3246 static HRESULT WINAPI IWineD3DDeviceImpl_GetBaseVertexIndex(IWineD3DDevice *iface, INT* base_index) {
3247 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3248 TRACE("(%p) : base_index %p\n", This, base_index);
3250 *base_index = This->stateBlock->baseVertexIndex;
3252 TRACE("Returning %u\n", *base_index);
3254 return WINED3D_OK;
3257 /*****
3258 * Get / Set Viewports
3259 *****/
3260 static HRESULT WINAPI IWineD3DDeviceImpl_SetViewport(IWineD3DDevice *iface, CONST WINED3DVIEWPORT* pViewport) {
3261 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3263 TRACE("(%p)\n", This);
3264 This->updateStateBlock->changed.viewport = TRUE;
3265 This->updateStateBlock->viewport = *pViewport;
3267 /* Handle recording of state blocks */
3268 if (This->isRecordingState) {
3269 TRACE("Recording... not performing anything\n");
3270 return WINED3D_OK;
3273 TRACE("(%p) : x=%d, y=%d, wid=%d, hei=%d, minz=%f, maxz=%f\n", This,
3274 pViewport->X, pViewport->Y, pViewport->Width, pViewport->Height, pViewport->MinZ, pViewport->MaxZ);
3276 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
3277 return WINED3D_OK;
3281 static HRESULT WINAPI IWineD3DDeviceImpl_GetViewport(IWineD3DDevice *iface, WINED3DVIEWPORT* pViewport) {
3282 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3283 TRACE("(%p)\n", This);
3284 *pViewport = This->stateBlock->viewport;
3285 return WINED3D_OK;
3288 /*****
3289 * Get / Set Render States
3290 * TODO: Verify against dx9 definitions
3291 *****/
3292 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD Value) {
3294 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3295 DWORD oldValue = This->stateBlock->renderState[State];
3297 TRACE("(%p)->state = %s(%d), value = %d\n", This, debug_d3drenderstate(State), State, Value);
3299 This->updateStateBlock->changed.renderState[State] = TRUE;
3300 This->updateStateBlock->renderState[State] = Value;
3302 /* Handle recording of state blocks */
3303 if (This->isRecordingState) {
3304 TRACE("Recording... not performing anything\n");
3305 return WINED3D_OK;
3308 /* Compared here and not before the assignment to allow proper stateblock recording */
3309 if(Value == oldValue) {
3310 TRACE("Application is setting the old value over, nothing to do\n");
3311 } else {
3312 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(State));
3315 return WINED3D_OK;
3318 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderState(IWineD3DDevice *iface, WINED3DRENDERSTATETYPE State, DWORD *pValue) {
3319 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3320 TRACE("(%p) for State %d = %d\n", This, State, This->stateBlock->renderState[State]);
3321 *pValue = This->stateBlock->renderState[State];
3322 return WINED3D_OK;
3325 /*****
3326 * Get / Set Sampler States
3327 * TODO: Verify against dx9 definitions
3328 *****/
3330 static HRESULT WINAPI IWineD3DDeviceImpl_SetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD Value) {
3331 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3332 DWORD oldValue;
3334 TRACE("(%p) : Sampler %#x, Type %s (%#x), Value %#x\n",
3335 This, Sampler, debug_d3dsamplerstate(Type), Type, Value);
3337 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3338 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3341 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3342 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3343 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3346 * SetSampler is designed to allow for more than the standard up to 8 textures
3347 * and Geforce has stopped supporting more than 6 standard textures in openGL.
3348 * So I have to use ARB for Gforce. (maybe if the sampler > 4 then use ARB?)
3350 * http://developer.nvidia.com/object/General_FAQ.html#t6
3352 * There are two new settings for GForce
3353 * the sampler one:
3354 * GL_MAX_TEXTURE_IMAGE_UNITS_ARB
3355 * and the texture one:
3356 * GL_MAX_TEXTURE_COORDS_ARB.
3357 * Ok GForce say it's ok to use glTexParameter/glGetTexParameter(...).
3358 ******************/
3360 oldValue = This->stateBlock->samplerState[Sampler][Type];
3361 This->updateStateBlock->samplerState[Sampler][Type] = Value;
3362 This->updateStateBlock->changed.samplerState[Sampler][Type] = Value;
3364 /* Handle recording of state blocks */
3365 if (This->isRecordingState) {
3366 TRACE("Recording... not performing anything\n");
3367 return WINED3D_OK;
3370 if(oldValue == Value) {
3371 TRACE("Application is setting the old value over, nothing to do\n");
3372 return WINED3D_OK;
3375 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Sampler));
3377 return WINED3D_OK;
3380 static HRESULT WINAPI IWineD3DDeviceImpl_GetSamplerState(IWineD3DDevice *iface, DWORD Sampler, WINED3DSAMPLERSTATETYPE Type, DWORD* Value) {
3381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3383 TRACE("(%p) : Sampler %#x, Type %s (%#x)\n",
3384 This, Sampler, debug_d3dsamplerstate(Type), Type);
3386 if (Sampler >= WINED3DVERTEXTEXTURESAMPLER0 && Sampler <= WINED3DVERTEXTEXTURESAMPLER3) {
3387 Sampler -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
3390 if (Sampler >= sizeof(This->stateBlock->samplerState)/sizeof(This->stateBlock->samplerState[0])) {
3391 ERR("Current Sampler overflows sampleState0 array (sampler %d)\n", Sampler);
3392 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
3394 *Value = This->stateBlock->samplerState[Sampler][Type];
3395 TRACE("(%p) : Returning %#x\n", This, *Value);
3397 return WINED3D_OK;
3400 static HRESULT WINAPI IWineD3DDeviceImpl_SetScissorRect(IWineD3DDevice *iface, CONST RECT* pRect) {
3401 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3403 This->updateStateBlock->changed.scissorRect = TRUE;
3404 if(EqualRect(&This->updateStateBlock->scissorRect, pRect)) {
3405 TRACE("App is setting the old scissor rectangle over, nothing to do\n");
3406 return WINED3D_OK;
3408 CopyRect(&This->updateStateBlock->scissorRect, pRect);
3410 if(This->isRecordingState) {
3411 TRACE("Recording... not performing anything\n");
3412 return WINED3D_OK;
3415 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
3417 return WINED3D_OK;
3420 static HRESULT WINAPI IWineD3DDeviceImpl_GetScissorRect(IWineD3DDevice *iface, RECT* pRect) {
3421 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3423 *pRect = This->updateStateBlock->scissorRect;
3424 TRACE("(%p)Returning a Scissor Rect of %d:%d-%d:%d\n", This, pRect->left, pRect->top, pRect->right, pRect->bottom);
3425 return WINED3D_OK;
3428 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration* pDecl) {
3429 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
3430 IWineD3DVertexDeclaration *oldDecl = This->updateStateBlock->vertexDecl;
3432 TRACE("(%p) : pDecl=%p\n", This, pDecl);
3434 This->updateStateBlock->vertexDecl = pDecl;
3435 This->updateStateBlock->changed.vertexDecl = TRUE;
3437 if (This->isRecordingState) {
3438 TRACE("Recording... not performing anything\n");
3439 return WINED3D_OK;
3440 } else if(pDecl == oldDecl) {
3441 /* Checked after the assignment to allow proper stateblock recording */
3442 TRACE("Application is setting the old declaration over, nothing to do\n");
3443 return WINED3D_OK;
3446 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
3447 return WINED3D_OK;
3450 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexDeclaration(IWineD3DDevice* iface, IWineD3DVertexDeclaration** ppDecl) {
3451 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3453 TRACE("(%p) : ppDecl=%p\n", This, ppDecl);
3455 *ppDecl = This->stateBlock->vertexDecl;
3456 if (NULL != *ppDecl) IWineD3DVertexDeclaration_AddRef(*ppDecl);
3457 return WINED3D_OK;
3460 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader* pShader) {
3461 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3462 IWineD3DVertexShader* oldShader = This->updateStateBlock->vertexShader;
3464 This->updateStateBlock->vertexShader = pShader;
3465 This->updateStateBlock->changed.vertexShader = TRUE;
3467 if (This->isRecordingState) {
3468 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3469 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3470 TRACE("Recording... not performing anything\n");
3471 return WINED3D_OK;
3472 } else if(oldShader == pShader) {
3473 /* Checked here to allow proper stateblock recording */
3474 TRACE("App is setting the old shader over, nothing to do\n");
3475 return WINED3D_OK;
3478 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3479 if(pShader) IWineD3DVertexShader_AddRef(pShader);
3480 if(oldShader) IWineD3DVertexShader_Release(oldShader);
3482 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VSHADER);
3484 return WINED3D_OK;
3487 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShader(IWineD3DDevice *iface, IWineD3DVertexShader** ppShader) {
3488 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3490 if (NULL == ppShader) {
3491 return WINED3DERR_INVALIDCALL;
3493 *ppShader = This->stateBlock->vertexShader;
3494 if( NULL != *ppShader)
3495 IWineD3DVertexShader_AddRef(*ppShader);
3497 TRACE("(%p) : returning %p\n", This, *ppShader);
3498 return WINED3D_OK;
3501 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantB(
3502 IWineD3DDevice *iface,
3503 UINT start,
3504 CONST BOOL *srcData,
3505 UINT count) {
3507 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3508 int i, cnt = min(count, MAX_CONST_B - start);
3510 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3511 iface, srcData, start, count);
3513 if (srcData == NULL || cnt < 0)
3514 return WINED3DERR_INVALIDCALL;
3516 memcpy(&This->updateStateBlock->vertexShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3517 for (i = 0; i < cnt; i++)
3518 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3520 for (i = start; i < cnt + start; ++i) {
3521 This->updateStateBlock->changed.vertexShaderConstantsB[i] = TRUE;
3524 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3526 return WINED3D_OK;
3529 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantB(
3530 IWineD3DDevice *iface,
3531 UINT start,
3532 BOOL *dstData,
3533 UINT count) {
3535 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3536 int cnt = min(count, MAX_CONST_B - start);
3538 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3539 iface, dstData, start, count);
3541 if (dstData == NULL || cnt < 0)
3542 return WINED3DERR_INVALIDCALL;
3544 memcpy(dstData, &This->stateBlock->vertexShaderConstantB[start], cnt * sizeof(BOOL));
3545 return WINED3D_OK;
3548 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantI(
3549 IWineD3DDevice *iface,
3550 UINT start,
3551 CONST int *srcData,
3552 UINT count) {
3554 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3555 int i, cnt = min(count, MAX_CONST_I - start);
3557 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3558 iface, srcData, start, count);
3560 if (srcData == NULL || cnt < 0)
3561 return WINED3DERR_INVALIDCALL;
3563 memcpy(&This->updateStateBlock->vertexShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3564 for (i = 0; i < cnt; i++)
3565 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3566 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3568 for (i = start; i < cnt + start; ++i) {
3569 This->updateStateBlock->changed.vertexShaderConstantsI[i] = TRUE;
3572 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3574 return WINED3D_OK;
3577 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantI(
3578 IWineD3DDevice *iface,
3579 UINT start,
3580 int *dstData,
3581 UINT count) {
3583 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3584 int cnt = min(count, MAX_CONST_I - start);
3586 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3587 iface, dstData, start, count);
3589 if (dstData == NULL || ((signed int) MAX_CONST_I - (signed int) start) <= (signed int) 0)
3590 return WINED3DERR_INVALIDCALL;
3592 memcpy(dstData, &This->stateBlock->vertexShaderConstantI[start * 4], cnt * sizeof(int) * 4);
3593 return WINED3D_OK;
3596 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF(
3597 IWineD3DDevice *iface,
3598 UINT start,
3599 CONST float *srcData,
3600 UINT count) {
3602 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3603 int i;
3605 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3606 iface, srcData, start, count);
3608 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3609 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3610 return WINED3DERR_INVALIDCALL;
3612 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3613 if(TRACE_ON(d3d)) {
3614 for (i = 0; i < count; i++)
3615 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3616 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3619 for (i = start; i < count + start; ++i) {
3620 if (!This->updateStateBlock->changed.vertexShaderConstantsF[i]) {
3621 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_vconstantsF), constants_entry, entry);
3622 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
3623 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
3624 list_add_head(&This->updateStateBlock->set_vconstantsF, &ptr->entry);
3626 ptr->idx[ptr->count++] = i;
3627 This->updateStateBlock->changed.vertexShaderConstantsF[i] = TRUE;
3631 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3633 return WINED3D_OK;
3636 static HRESULT WINAPI IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst(
3637 IWineD3DDevice *iface,
3638 UINT start,
3639 CONST float *srcData,
3640 UINT count) {
3642 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3643 int i;
3645 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3646 iface, srcData, start, count);
3648 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
3649 if (srcData == NULL || start + count > GL_LIMITS(vshader_constantsF) || start > GL_LIMITS(vshader_constantsF))
3650 return WINED3DERR_INVALIDCALL;
3652 memcpy(&This->updateStateBlock->vertexShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
3653 if(TRACE_ON(d3d)) {
3654 for (i = 0; i < count; i++)
3655 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
3656 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3659 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
3660 * context. On a context switch the old context will be fully dirtified
3662 memset(This->activeContext->vshader_const_dirty + start, 1,
3663 sizeof(*This->activeContext->vshader_const_dirty) * count);
3664 This->highest_dirty_vs_const = max(This->highest_dirty_vs_const, start+count+1);
3666 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VERTEXSHADERCONSTANT);
3668 return WINED3D_OK;
3671 static HRESULT WINAPI IWineD3DDeviceImpl_GetVertexShaderConstantF(
3672 IWineD3DDevice *iface,
3673 UINT start,
3674 float *dstData,
3675 UINT count) {
3677 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3678 int cnt = min(count, GL_LIMITS(vshader_constantsF) - start);
3680 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3681 iface, dstData, start, count);
3683 if (dstData == NULL || cnt < 0)
3684 return WINED3DERR_INVALIDCALL;
3686 memcpy(dstData, &This->stateBlock->vertexShaderConstantF[start * 4], cnt * sizeof(float) * 4);
3687 return WINED3D_OK;
3690 static inline void markTextureStagesDirty(IWineD3DDeviceImpl *This, DWORD stage) {
3691 DWORD i;
3692 for(i = 0; i < WINED3D_HIGHEST_TEXTURE_STATE; i++) {
3693 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(stage, i));
3697 static void device_map_stage(IWineD3DDeviceImpl *This, int stage, int unit) {
3698 int i = This->rev_tex_unit_map[unit];
3699 int j = This->texUnitMap[stage];
3701 This->texUnitMap[stage] = unit;
3702 if (i != -1 && i != stage) {
3703 This->texUnitMap[i] = -1;
3706 This->rev_tex_unit_map[unit] = stage;
3707 if (j != -1 && j != unit) {
3708 This->rev_tex_unit_map[j] = -1;
3712 static void device_update_fixed_function_usage_map(IWineD3DDeviceImpl *This) {
3713 int i;
3715 for (i = 0; i < MAX_TEXTURES; ++i) {
3716 WINED3DTEXTUREOP color_op = This->stateBlock->textureState[i][WINED3DTSS_COLOROP];
3717 WINED3DTEXTUREOP alpha_op = This->stateBlock->textureState[i][WINED3DTSS_ALPHAOP];
3718 DWORD color_arg1 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG1] & WINED3DTA_SELECTMASK;
3719 DWORD color_arg2 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG2] & WINED3DTA_SELECTMASK;
3720 DWORD color_arg3 = This->stateBlock->textureState[i][WINED3DTSS_COLORARG0] & WINED3DTA_SELECTMASK;
3721 DWORD alpha_arg1 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG1] & WINED3DTA_SELECTMASK;
3722 DWORD alpha_arg2 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG2] & WINED3DTA_SELECTMASK;
3723 DWORD alpha_arg3 = This->stateBlock->textureState[i][WINED3DTSS_ALPHAARG0] & WINED3DTA_SELECTMASK;
3725 if (color_op == WINED3DTOP_DISABLE) {
3726 /* Not used, and disable higher stages */
3727 while (i < MAX_TEXTURES) {
3728 This->fixed_function_usage_map[i] = FALSE;
3729 ++i;
3731 break;
3734 if (((color_arg1 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG2)
3735 || ((color_arg2 == WINED3DTA_TEXTURE) && color_op != WINED3DTOP_SELECTARG1)
3736 || ((color_arg3 == WINED3DTA_TEXTURE) && (color_op == WINED3DTOP_MULTIPLYADD || color_op == WINED3DTOP_LERP))
3737 || ((alpha_arg1 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG2)
3738 || ((alpha_arg2 == WINED3DTA_TEXTURE) && alpha_op != WINED3DTOP_SELECTARG1)
3739 || ((alpha_arg3 == WINED3DTA_TEXTURE) && (alpha_op == WINED3DTOP_MULTIPLYADD || alpha_op == WINED3DTOP_LERP))) {
3740 This->fixed_function_usage_map[i] = TRUE;
3741 } else {
3742 This->fixed_function_usage_map[i] = FALSE;
3745 if ((color_op == WINED3DTOP_BUMPENVMAP || color_op == WINED3DTOP_BUMPENVMAPLUMINANCE) && i < MAX_TEXTURES - 1) {
3746 This->fixed_function_usage_map[i+1] = TRUE;
3751 static void device_map_fixed_function_samplers(IWineD3DDeviceImpl *This) {
3752 int i, tex;
3754 device_update_fixed_function_usage_map(This);
3756 if (This->max_ffp_textures == This->max_ffp_texture_stages ||
3757 This->stateBlock->lowest_disabled_stage <= This->max_ffp_textures) {
3758 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3759 if (!This->fixed_function_usage_map[i]) continue;
3761 if (This->texUnitMap[i] != i) {
3762 device_map_stage(This, i, i);
3763 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3764 markTextureStagesDirty(This, i);
3767 return;
3770 /* Now work out the mapping */
3771 tex = 0;
3772 for (i = 0; i < This->stateBlock->lowest_disabled_stage; ++i) {
3773 if (!This->fixed_function_usage_map[i]) continue;
3775 if (This->texUnitMap[i] != tex) {
3776 device_map_stage(This, i, tex);
3777 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3778 markTextureStagesDirty(This, i);
3781 ++tex;
3785 static void device_map_psamplers(IWineD3DDeviceImpl *This) {
3786 DWORD *sampler_tokens = ((IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader)->baseShader.reg_maps.samplers;
3787 int i;
3789 for (i = 0; i < MAX_FRAGMENT_SAMPLERS; ++i) {
3790 if (sampler_tokens[i] && This->texUnitMap[i] != i) {
3791 device_map_stage(This, i, i);
3792 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(i));
3793 if (i < MAX_TEXTURES) {
3794 markTextureStagesDirty(This, i);
3800 static BOOL device_unit_free_for_vs(IWineD3DDeviceImpl *This, DWORD *pshader_sampler_tokens, DWORD *vshader_sampler_tokens, int unit) {
3801 int current_mapping = This->rev_tex_unit_map[unit];
3803 if (current_mapping == -1) {
3804 /* Not currently used */
3805 return TRUE;
3808 if (current_mapping < MAX_FRAGMENT_SAMPLERS) {
3809 /* Used by a fragment sampler */
3811 if (!pshader_sampler_tokens) {
3812 /* No pixel shader, check fixed function */
3813 return current_mapping >= MAX_TEXTURES || !This->fixed_function_usage_map[current_mapping];
3816 /* Pixel shader, check the shader's sampler map */
3817 return !pshader_sampler_tokens[current_mapping];
3820 /* Used by a vertex sampler */
3821 return !vshader_sampler_tokens[current_mapping];
3824 static void device_map_vsamplers(IWineD3DDeviceImpl *This, BOOL ps) {
3825 DWORD *vshader_sampler_tokens = ((IWineD3DVertexShaderImpl *)This->stateBlock->vertexShader)->baseShader.reg_maps.samplers;
3826 DWORD *pshader_sampler_tokens = NULL;
3827 int start = GL_LIMITS(combined_samplers) - 1;
3828 int i;
3830 if (ps) {
3831 IWineD3DPixelShaderImpl *pshader = (IWineD3DPixelShaderImpl *)This->stateBlock->pixelShader;
3833 /* Make sure the shader's reg_maps are up to date. This is only relevant for 1.x pixelshaders. */
3834 IWineD3DPixelShader_CompileShader((IWineD3DPixelShader *)pshader);
3835 pshader_sampler_tokens = pshader->baseShader.reg_maps.samplers;
3838 for (i = 0; i < MAX_VERTEX_SAMPLERS; ++i) {
3839 int vsampler_idx = i + MAX_FRAGMENT_SAMPLERS;
3840 if (vshader_sampler_tokens[i]) {
3841 if (This->texUnitMap[vsampler_idx] != -1) {
3842 /* Already mapped somewhere */
3843 continue;
3846 while (start >= 0) {
3847 if (device_unit_free_for_vs(This, pshader_sampler_tokens, vshader_sampler_tokens, start)) {
3848 device_map_stage(This, vsampler_idx, start);
3849 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(vsampler_idx));
3851 --start;
3852 break;
3855 --start;
3861 void IWineD3DDeviceImpl_FindTexUnitMap(IWineD3DDeviceImpl *This) {
3862 BOOL vs = use_vs(This);
3863 BOOL ps = use_ps(This);
3865 * Rules are:
3866 * -> Pixel shaders need a 1:1 map. In theory the shader input could be mapped too, but
3867 * that would be really messy and require shader recompilation
3868 * -> When the mapping of a stage is changed, sampler and ALL texture stage states have
3869 * to be reset. Because of that try to work with a 1:1 mapping as much as possible
3871 if (ps) {
3872 device_map_psamplers(This);
3873 } else {
3874 device_map_fixed_function_samplers(This);
3877 if (vs) {
3878 device_map_vsamplers(This, ps);
3882 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader *pShader) {
3883 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3884 IWineD3DPixelShader *oldShader = This->updateStateBlock->pixelShader;
3885 This->updateStateBlock->pixelShader = pShader;
3886 This->updateStateBlock->changed.pixelShader = TRUE;
3888 /* Handle recording of state blocks */
3889 if (This->isRecordingState) {
3890 TRACE("Recording... not performing anything\n");
3893 if (This->isRecordingState) {
3894 TRACE("Recording... not performing anything\n");
3895 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3896 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3897 return WINED3D_OK;
3900 if(pShader == oldShader) {
3901 TRACE("App is setting the old pixel shader over, nothing to do\n");
3902 return WINED3D_OK;
3905 if(pShader) IWineD3DPixelShader_AddRef(pShader);
3906 if(oldShader) IWineD3DPixelShader_Release(oldShader);
3908 TRACE("(%p) : setting pShader(%p)\n", This, pShader);
3909 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADER);
3911 return WINED3D_OK;
3914 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShader(IWineD3DDevice *iface, IWineD3DPixelShader **ppShader) {
3915 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3917 if (NULL == ppShader) {
3918 WARN("(%p) : PShader is NULL, returning INVALIDCALL\n", This);
3919 return WINED3DERR_INVALIDCALL;
3922 *ppShader = This->stateBlock->pixelShader;
3923 if (NULL != *ppShader) {
3924 IWineD3DPixelShader_AddRef(*ppShader);
3926 TRACE("(%p) : returning %p\n", This, *ppShader);
3927 return WINED3D_OK;
3930 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantB(
3931 IWineD3DDevice *iface,
3932 UINT start,
3933 CONST BOOL *srcData,
3934 UINT count) {
3936 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3937 int i, cnt = min(count, MAX_CONST_B - start);
3939 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3940 iface, srcData, start, count);
3942 if (srcData == NULL || cnt < 0)
3943 return WINED3DERR_INVALIDCALL;
3945 memcpy(&This->updateStateBlock->pixelShaderConstantB[start], srcData, cnt * sizeof(BOOL));
3946 for (i = 0; i < cnt; i++)
3947 TRACE("Set BOOL constant %u to %s\n", start + i, srcData[i]? "true":"false");
3949 for (i = start; i < cnt + start; ++i) {
3950 This->updateStateBlock->changed.pixelShaderConstantsB[i] = TRUE;
3953 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
3955 return WINED3D_OK;
3958 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantB(
3959 IWineD3DDevice *iface,
3960 UINT start,
3961 BOOL *dstData,
3962 UINT count) {
3964 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3965 int cnt = min(count, MAX_CONST_B - start);
3967 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
3968 iface, dstData, start, count);
3970 if (dstData == NULL || cnt < 0)
3971 return WINED3DERR_INVALIDCALL;
3973 memcpy(dstData, &This->stateBlock->pixelShaderConstantB[start], cnt * sizeof(BOOL));
3974 return WINED3D_OK;
3977 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantI(
3978 IWineD3DDevice *iface,
3979 UINT start,
3980 CONST int *srcData,
3981 UINT count) {
3983 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
3984 int i, cnt = min(count, MAX_CONST_I - start);
3986 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
3987 iface, srcData, start, count);
3989 if (srcData == NULL || cnt < 0)
3990 return WINED3DERR_INVALIDCALL;
3992 memcpy(&This->updateStateBlock->pixelShaderConstantI[start * 4], srcData, cnt * sizeof(int) * 4);
3993 for (i = 0; i < cnt; i++)
3994 TRACE("Set INT constant %u to { %d, %d, %d, %d }\n", start + i,
3995 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
3997 for (i = start; i < cnt + start; ++i) {
3998 This->updateStateBlock->changed.pixelShaderConstantsI[i] = TRUE;
4001 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4003 return WINED3D_OK;
4006 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantI(
4007 IWineD3DDevice *iface,
4008 UINT start,
4009 int *dstData,
4010 UINT count) {
4012 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4013 int cnt = min(count, MAX_CONST_I - start);
4015 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4016 iface, dstData, start, count);
4018 if (dstData == NULL || cnt < 0)
4019 return WINED3DERR_INVALIDCALL;
4021 memcpy(dstData, &This->stateBlock->pixelShaderConstantI[start * 4], cnt * sizeof(int) * 4);
4022 return WINED3D_OK;
4025 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF(
4026 IWineD3DDevice *iface,
4027 UINT start,
4028 CONST float *srcData,
4029 UINT count) {
4031 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4032 int i;
4034 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4035 iface, srcData, start, count);
4037 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4038 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4039 return WINED3DERR_INVALIDCALL;
4041 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4042 if(TRACE_ON(d3d)) {
4043 for (i = 0; i < count; i++)
4044 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4045 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4048 for (i = start; i < count + start; ++i) {
4049 if (!This->updateStateBlock->changed.pixelShaderConstantsF[i]) {
4050 constants_entry *ptr = LIST_ENTRY(list_head(&This->updateStateBlock->set_pconstantsF), constants_entry, entry);
4051 if (!ptr || ptr->count >= sizeof(ptr->idx) / sizeof(*ptr->idx)) {
4052 ptr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(constants_entry));
4053 list_add_head(&This->updateStateBlock->set_pconstantsF, &ptr->entry);
4055 ptr->idx[ptr->count++] = i;
4056 This->updateStateBlock->changed.pixelShaderConstantsF[i] = TRUE;
4060 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4062 return WINED3D_OK;
4065 static HRESULT WINAPI IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst(
4066 IWineD3DDevice *iface,
4067 UINT start,
4068 CONST float *srcData,
4069 UINT count) {
4071 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4072 int i;
4074 TRACE("(iface %p, srcData %p, start %d, count %d)\n",
4075 iface, srcData, start, count);
4077 /* Specifically test start > limit to catch MAX_UINT overflows when adding start + count */
4078 if (srcData == NULL || start + count > GL_LIMITS(pshader_constantsF) || start > GL_LIMITS(pshader_constantsF))
4079 return WINED3DERR_INVALIDCALL;
4081 memcpy(&This->updateStateBlock->pixelShaderConstantF[start * 4], srcData, count * sizeof(float) * 4);
4082 if(TRACE_ON(d3d)) {
4083 for (i = 0; i < count; i++)
4084 TRACE("Set FLOAT constant %u to { %f, %f, %f, %f }\n", start + i,
4085 srcData[i*4], srcData[i*4+1], srcData[i*4+2], srcData[i*4+3]);
4088 /* We don't want shader constant dirtification to be an O(contexts), so just dirtify the active
4089 * context. On a context switch the old context will be fully dirtified
4091 memset(This->activeContext->pshader_const_dirty + start, 1,
4092 sizeof(*This->activeContext->pshader_const_dirty) * count);
4093 This->highest_dirty_ps_const = max(This->highest_dirty_ps_const, start+count+1);
4095 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_PIXELSHADERCONSTANT);
4097 return WINED3D_OK;
4100 static HRESULT WINAPI IWineD3DDeviceImpl_GetPixelShaderConstantF(
4101 IWineD3DDevice *iface,
4102 UINT start,
4103 float *dstData,
4104 UINT count) {
4106 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4107 int cnt = min(count, GL_LIMITS(pshader_constantsF) - start);
4109 TRACE("(iface %p, dstData %p, start %d, count %d)\n",
4110 iface, dstData, start, count);
4112 if (dstData == NULL || cnt < 0)
4113 return WINED3DERR_INVALIDCALL;
4115 memcpy(dstData, &This->stateBlock->pixelShaderConstantF[start * 4], cnt * sizeof(float) * 4);
4116 return WINED3D_OK;
4119 #define copy_and_next(dest, src, size) memcpy(dest, src, size); dest += (size)
4120 static HRESULT
4121 process_vertices_strided(IWineD3DDeviceImpl *This, DWORD dwDestIndex, DWORD dwCount, WineDirect3DVertexStridedData *lpStrideData, IWineD3DVertexBufferImpl *dest, DWORD dwFlags) {
4122 char *dest_ptr, *dest_conv = NULL, *dest_conv_addr = NULL;
4123 unsigned int i;
4124 DWORD DestFVF = dest->fvf;
4125 WINED3DVIEWPORT vp;
4126 WINED3DMATRIX mat, proj_mat, view_mat, world_mat;
4127 BOOL doClip;
4128 int numTextures;
4130 if (lpStrideData->u.s.normal.lpData) {
4131 WARN(" lighting state not saved yet... Some strange stuff may happen !\n");
4134 if (lpStrideData->u.s.position.lpData == NULL) {
4135 ERR("Source has no position mask\n");
4136 return WINED3DERR_INVALIDCALL;
4139 /* We might access VBOs from this code, so hold the lock */
4140 ENTER_GL();
4142 if (dest->resource.allocatedMemory == NULL) {
4143 /* This may happen if we do direct locking into a vbo. Unlikely,
4144 * but theoretically possible(ddraw processvertices test)
4146 dest->resource.allocatedMemory = HeapAlloc(GetProcessHeap(), 0, dest->resource.size);
4147 if(!dest->resource.allocatedMemory) {
4148 LEAVE_GL();
4149 ERR("Out of memory\n");
4150 return E_OUTOFMEMORY;
4152 if(dest->vbo) {
4153 void *src;
4154 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4155 checkGLcall("glBindBufferARB");
4156 src = GL_EXTCALL(glMapBufferARB(GL_ARRAY_BUFFER_ARB, GL_READ_ONLY_ARB));
4157 if(src) {
4158 memcpy(dest->resource.allocatedMemory, src, dest->resource.size);
4160 GL_EXTCALL(glUnmapBufferARB(GL_ARRAY_BUFFER_ARB));
4161 checkGLcall("glUnmapBufferARB");
4165 /* Get a pointer into the destination vbo(create one if none exists) and
4166 * write correct opengl data into it. It's cheap and allows us to run drawStridedFast
4168 if(!dest->vbo && GL_SUPPORT(ARB_VERTEX_BUFFER_OBJECT)) {
4169 dest->Flags |= VBFLAG_CREATEVBO;
4170 IWineD3DVertexBuffer_PreLoad((IWineD3DVertexBuffer *) dest);
4173 if(dest->vbo) {
4174 unsigned char extrabytes = 0;
4175 /* If the destination vertex buffer has D3DFVF_XYZ position(non-rhw), native d3d writes RHW position, where the RHW
4176 * gets written into the 4 bytes after the Z position. In the case of a dest buffer that only has D3DFVF_XYZ data,
4177 * this may write 4 extra bytes beyond the area that should be written
4179 if(DestFVF == WINED3DFVF_XYZ) extrabytes = 4;
4180 dest_conv_addr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwCount * get_flexible_vertex_size(DestFVF) + extrabytes);
4181 if(!dest_conv_addr) {
4182 ERR("Out of memory\n");
4183 /* Continue without storing converted vertices */
4185 dest_conv = dest_conv_addr;
4188 /* Should I clip?
4189 * a) WINED3DRS_CLIPPING is enabled
4190 * b) WINED3DVOP_CLIP is passed
4192 if(This->stateBlock->renderState[WINED3DRS_CLIPPING]) {
4193 static BOOL warned = FALSE;
4195 * The clipping code is not quite correct. Some things need
4196 * to be checked against IDirect3DDevice3 (!), d3d8 and d3d9,
4197 * so disable clipping for now.
4198 * (The graphics in Half-Life are broken, and my processvertices
4199 * test crashes with IDirect3DDevice3)
4200 doClip = TRUE;
4202 doClip = FALSE;
4203 if(!warned) {
4204 warned = TRUE;
4205 FIXME("Clipping is broken and disabled for now\n");
4207 } else doClip = FALSE;
4208 dest_ptr = ((char *) dest->resource.allocatedMemory) + dwDestIndex * get_flexible_vertex_size(DestFVF);
4210 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4211 WINED3DTS_VIEW,
4212 &view_mat);
4213 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4214 WINED3DTS_PROJECTION,
4215 &proj_mat);
4216 IWineD3DDevice_GetTransform( (IWineD3DDevice *) This,
4217 WINED3DTS_WORLDMATRIX(0),
4218 &world_mat);
4220 TRACE("View mat:\n");
4221 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);
4222 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);
4223 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);
4224 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);
4226 TRACE("Proj mat:\n");
4227 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);
4228 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);
4229 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);
4230 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);
4232 TRACE("World mat:\n");
4233 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);
4234 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);
4235 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);
4236 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);
4238 /* Get the viewport */
4239 IWineD3DDevice_GetViewport( (IWineD3DDevice *) This, &vp);
4240 TRACE("Viewport: X=%d, Y=%d, Width=%d, Height=%d, MinZ=%f, MaxZ=%f\n",
4241 vp.X, vp.Y, vp.Width, vp.Height, vp.MinZ, vp.MaxZ);
4243 multiply_matrix(&mat,&view_mat,&world_mat);
4244 multiply_matrix(&mat,&proj_mat,&mat);
4246 numTextures = (DestFVF & WINED3DFVF_TEXCOUNT_MASK) >> WINED3DFVF_TEXCOUNT_SHIFT;
4248 for (i = 0; i < dwCount; i+= 1) {
4249 unsigned int tex_index;
4251 if ( ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZ ) ||
4252 ((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW ) ) {
4253 /* The position first */
4254 float *p =
4255 (float *) (((char *) lpStrideData->u.s.position.lpData) + i * lpStrideData->u.s.position.dwStride);
4256 float x, y, z, rhw;
4257 TRACE("In: ( %06.2f %06.2f %06.2f )\n", p[0], p[1], p[2]);
4259 /* Multiplication with world, view and projection matrix */
4260 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);
4261 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);
4262 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);
4263 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);
4265 TRACE("x=%f y=%f z=%f rhw=%f\n", x, y, z, rhw);
4267 /* WARNING: The following things are taken from d3d7 and were not yet checked
4268 * against d3d8 or d3d9!
4271 /* Clipping conditions: From msdn
4273 * A vertex is clipped if it does not match the following requirements
4274 * -rhw < x <= rhw
4275 * -rhw < y <= rhw
4276 * 0 < z <= rhw
4277 * 0 < rhw ( Not in d3d7, but tested in d3d7)
4279 * If clipping is on is determined by the D3DVOP_CLIP flag in D3D7, and
4280 * by the D3DRS_CLIPPING in D3D9(according to the msdn, not checked)
4284 if( !doClip ||
4285 ( (-rhw -eps < x) && (-rhw -eps < y) && ( -eps < z) &&
4286 (x <= rhw + eps) && (y <= rhw + eps ) && (z <= rhw + eps) &&
4287 ( rhw > eps ) ) ) {
4289 /* "Normal" viewport transformation (not clipped)
4290 * 1) The values are divided by rhw
4291 * 2) The y axis is negative, so multiply it with -1
4292 * 3) Screen coordinates go from -(Width/2) to +(Width/2) and
4293 * -(Height/2) to +(Height/2). The z range is MinZ to MaxZ
4294 * 4) Multiply x with Width/2 and add Width/2
4295 * 5) The same for the height
4296 * 6) Add the viewpoint X and Y to the 2D coordinates and
4297 * The minimum Z value to z
4298 * 7) rhw = 1 / rhw Reciprocal of Homogeneous W....
4300 * Well, basically it's simply a linear transformation into viewport
4301 * coordinates
4304 x /= rhw;
4305 y /= rhw;
4306 z /= rhw;
4308 y *= -1;
4310 x *= vp.Width / 2;
4311 y *= vp.Height / 2;
4312 z *= vp.MaxZ - vp.MinZ;
4314 x += vp.Width / 2 + vp.X;
4315 y += vp.Height / 2 + vp.Y;
4316 z += vp.MinZ;
4318 rhw = 1 / rhw;
4319 } else {
4320 /* That vertex got clipped
4321 * Contrary to OpenGL it is not dropped completely, it just
4322 * undergoes a different calculation.
4324 TRACE("Vertex got clipped\n");
4325 x += rhw;
4326 y += rhw;
4328 x /= 2;
4329 y /= 2;
4331 /* Msdn mentions that Direct3D9 keeps a list of clipped vertices
4332 * outside of the main vertex buffer memory. That needs some more
4333 * investigation...
4337 TRACE("Writing (%f %f %f) %f\n", x, y, z, rhw);
4340 ( (float *) dest_ptr)[0] = x;
4341 ( (float *) dest_ptr)[1] = y;
4342 ( (float *) dest_ptr)[2] = z;
4343 ( (float *) dest_ptr)[3] = rhw; /* SIC, see ddraw test! */
4345 dest_ptr += 3 * sizeof(float);
4347 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4348 dest_ptr += sizeof(float);
4351 if(dest_conv) {
4352 float w = 1 / rhw;
4353 ( (float *) dest_conv)[0] = x * w;
4354 ( (float *) dest_conv)[1] = y * w;
4355 ( (float *) dest_conv)[2] = z * w;
4356 ( (float *) dest_conv)[3] = w;
4358 dest_conv += 3 * sizeof(float);
4360 if((DestFVF & WINED3DFVF_POSITION_MASK) == WINED3DFVF_XYZRHW) {
4361 dest_conv += sizeof(float);
4365 if (DestFVF & WINED3DFVF_PSIZE) {
4366 dest_ptr += sizeof(DWORD);
4367 if(dest_conv) dest_conv += sizeof(DWORD);
4369 if (DestFVF & WINED3DFVF_NORMAL) {
4370 float *normal =
4371 (float *) (((float *) lpStrideData->u.s.normal.lpData) + i * lpStrideData->u.s.normal.dwStride);
4372 /* AFAIK this should go into the lighting information */
4373 FIXME("Didn't expect the destination to have a normal\n");
4374 copy_and_next(dest_ptr, normal, 3 * sizeof(float));
4375 if(dest_conv) {
4376 copy_and_next(dest_conv, normal, 3 * sizeof(float));
4380 if (DestFVF & WINED3DFVF_DIFFUSE) {
4381 DWORD *color_d =
4382 (DWORD *) (((char *) lpStrideData->u.s.diffuse.lpData) + i * lpStrideData->u.s.diffuse.dwStride);
4383 if(!color_d) {
4384 static BOOL warned = FALSE;
4386 if(!warned) {
4387 ERR("No diffuse color in source, but destination has one\n");
4388 warned = TRUE;
4391 *( (DWORD *) dest_ptr) = 0xffffffff;
4392 dest_ptr += sizeof(DWORD);
4394 if(dest_conv) {
4395 *( (DWORD *) dest_conv) = 0xffffffff;
4396 dest_conv += sizeof(DWORD);
4399 else {
4400 copy_and_next(dest_ptr, color_d, sizeof(DWORD));
4401 if(dest_conv) {
4402 *( (DWORD *) dest_conv) = (*color_d & 0xff00ff00) ; /* Alpha + green */
4403 *( (DWORD *) dest_conv) |= (*color_d & 0x00ff0000) >> 16; /* Red */
4404 *( (DWORD *) dest_conv) |= (*color_d & 0xff0000ff) << 16; /* Blue */
4405 dest_conv += sizeof(DWORD);
4410 if (DestFVF & WINED3DFVF_SPECULAR) {
4411 /* What's the color value in the feedback buffer? */
4412 DWORD *color_s =
4413 (DWORD *) (((char *) lpStrideData->u.s.specular.lpData) + i * lpStrideData->u.s.specular.dwStride);
4414 if(!color_s) {
4415 static BOOL warned = FALSE;
4417 if(!warned) {
4418 ERR("No specular color in source, but destination has one\n");
4419 warned = TRUE;
4422 *( (DWORD *) dest_ptr) = 0xFF000000;
4423 dest_ptr += sizeof(DWORD);
4425 if(dest_conv) {
4426 *( (DWORD *) dest_conv) = 0xFF000000;
4427 dest_conv += sizeof(DWORD);
4430 else {
4431 copy_and_next(dest_ptr, color_s, sizeof(DWORD));
4432 if(dest_conv) {
4433 *( (DWORD *) dest_conv) = (*color_s & 0xff00ff00) ; /* Alpha + green */
4434 *( (DWORD *) dest_conv) |= (*color_s & 0x00ff0000) >> 16; /* Red */
4435 *( (DWORD *) dest_conv) |= (*color_s & 0xff0000ff) << 16; /* Blue */
4436 dest_conv += sizeof(DWORD);
4441 for (tex_index = 0; tex_index < numTextures; tex_index++) {
4442 float *tex_coord =
4443 (float *) (((char *) lpStrideData->u.s.texCoords[tex_index].lpData) +
4444 i * lpStrideData->u.s.texCoords[tex_index].dwStride);
4445 if(!tex_coord) {
4446 ERR("No source texture, but destination requests one\n");
4447 dest_ptr+=GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4448 if(dest_conv) dest_conv += GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float);
4450 else {
4451 copy_and_next(dest_ptr, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4452 if(dest_conv) {
4453 copy_and_next(dest_conv, tex_coord, GET_TEXCOORD_SIZE_FROM_FVF(DestFVF, tex_index) * sizeof(float));
4459 if(dest_conv) {
4460 GL_EXTCALL(glBindBufferARB(GL_ARRAY_BUFFER_ARB, dest->vbo));
4461 checkGLcall("glBindBufferARB(GL_ARRAY_BUFFER_ARB)");
4462 GL_EXTCALL(glBufferSubDataARB(GL_ARRAY_BUFFER_ARB, dwDestIndex * get_flexible_vertex_size(DestFVF),
4463 dwCount * get_flexible_vertex_size(DestFVF),
4464 dest_conv_addr));
4465 checkGLcall("glBufferSubDataARB(GL_ARRAY_BUFFER_ARB)");
4466 HeapFree(GetProcessHeap(), 0, dest_conv_addr);
4469 LEAVE_GL();
4471 return WINED3D_OK;
4473 #undef copy_and_next
4475 static HRESULT WINAPI IWineD3DDeviceImpl_ProcessVertices(IWineD3DDevice *iface, UINT SrcStartIndex, UINT DestIndex, UINT VertexCount, IWineD3DVertexBuffer* pDestBuffer, IWineD3DVertexDeclaration* pVertexDecl, DWORD Flags) {
4476 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4477 WineDirect3DVertexStridedData strided;
4478 BOOL vbo = FALSE, streamWasUP = This->stateBlock->streamIsUP;
4479 TRACE("(%p)->(%d,%d,%d,%p,%p,%d\n", This, SrcStartIndex, DestIndex, VertexCount, pDestBuffer, pVertexDecl, Flags);
4481 if(pVertexDecl) {
4482 ERR("Output vertex declaration not implemented yet\n");
4485 /* Need any context to write to the vbo. */
4486 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4488 /* ProcessVertices reads from vertex buffers, which have to be assigned. DrawPrimitive and DrawPrimitiveUP
4489 * control the streamIsUP flag, thus restore it afterwards.
4491 This->stateBlock->streamIsUP = FALSE;
4492 memset(&strided, 0, sizeof(strided));
4493 primitiveDeclarationConvertToStridedData(iface, FALSE, &strided, &vbo);
4494 This->stateBlock->streamIsUP = streamWasUP;
4496 if(vbo || SrcStartIndex) {
4497 unsigned int i;
4498 /* ProcessVertices can't convert FROM a vbo, and vertex buffers used to source into ProcessVertices are
4499 * unlikely to ever be used for drawing. Release vbos in those buffers and fix up the strided structure
4501 * Also get the start index in, but only loop over all elements if there's something to add at all.
4503 #define FIXSRC(type) \
4504 if(strided.u.s.type.VBO) { \
4505 IWineD3DVertexBufferImpl *vb = (IWineD3DVertexBufferImpl *) This->stateBlock->streamSource[strided.u.s.type.streamNo]; \
4506 strided.u.s.type.VBO = 0; \
4507 strided.u.s.type.lpData = (BYTE *) ((unsigned long) strided.u.s.type.lpData + (unsigned long) vb->resource.allocatedMemory); \
4508 ENTER_GL(); \
4509 GL_EXTCALL(glDeleteBuffersARB(1, &vb->vbo)); \
4510 vb->vbo = 0; \
4511 LEAVE_GL(); \
4513 if(strided.u.s.type.lpData) { \
4514 strided.u.s.type.lpData += strided.u.s.type.dwStride * SrcStartIndex; \
4516 FIXSRC(position);
4517 FIXSRC(blendWeights);
4518 FIXSRC(blendMatrixIndices);
4519 FIXSRC(normal);
4520 FIXSRC(pSize);
4521 FIXSRC(diffuse);
4522 FIXSRC(specular);
4523 for(i = 0; i < WINED3DDP_MAXTEXCOORD; i++) {
4524 FIXSRC(texCoords[i]);
4526 FIXSRC(position2);
4527 FIXSRC(normal2);
4528 FIXSRC(tangent);
4529 FIXSRC(binormal);
4530 FIXSRC(tessFactor);
4531 FIXSRC(fog);
4532 FIXSRC(depth);
4533 FIXSRC(sample);
4534 #undef FIXSRC
4537 return process_vertices_strided(This, DestIndex, VertexCount, &strided, (IWineD3DVertexBufferImpl *) pDestBuffer, Flags);
4540 /*****
4541 * Get / Set Texture Stage States
4542 * TODO: Verify against dx9 definitions
4543 *****/
4544 static HRESULT WINAPI IWineD3DDeviceImpl_SetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD Value) {
4545 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4546 DWORD oldValue = This->updateStateBlock->textureState[Stage][Type];
4548 TRACE("(%p) : Stage=%d, Type=%s(%d), Value=%d\n", This, Stage, debug_d3dtexturestate(Type), Type, Value);
4550 if (Stage >= MAX_TEXTURES) {
4551 WARN("Attempting to set stage %u which is higher than the max stage %u, ignoring\n", Stage, MAX_TEXTURES - 1);
4552 return WINED3D_OK;
4555 This->updateStateBlock->changed.textureState[Stage][Type] = TRUE;
4556 This->updateStateBlock->textureState[Stage][Type] = Value;
4558 if (This->isRecordingState) {
4559 TRACE("Recording... not performing anything\n");
4560 return WINED3D_OK;
4563 /* Checked after the assignments to allow proper stateblock recording */
4564 if(oldValue == Value) {
4565 TRACE("App is setting the old value over, nothing to do\n");
4566 return WINED3D_OK;
4569 if(Stage > This->stateBlock->lowest_disabled_stage &&
4570 This->StateTable[STATE_TEXTURESTAGE(0, Type)].representative == STATE_TEXTURESTAGE(0, WINED3DTSS_COLOROP)) {
4571 /* Colorop change above lowest disabled stage? That won't change anything in the gl setup
4572 * Changes in other states are important on disabled stages too
4574 return WINED3D_OK;
4577 if(Type == WINED3DTSS_COLOROP) {
4578 int i;
4580 if(Value == WINED3DTOP_DISABLE && oldValue != WINED3DTOP_DISABLE) {
4581 /* Previously enabled stage disabled now. Make sure to dirtify all enabled stages above Stage,
4582 * they have to be disabled
4584 * The current stage is dirtified below.
4586 for(i = Stage + 1; i < This->stateBlock->lowest_disabled_stage; i++) {
4587 TRACE("Additionally dirtifying stage %d\n", i);
4588 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4590 This->stateBlock->lowest_disabled_stage = Stage;
4591 TRACE("New lowest disabled: %d\n", Stage);
4592 } else if(Value != WINED3DTOP_DISABLE && oldValue == WINED3DTOP_DISABLE) {
4593 /* Previously disabled stage enabled. Stages above it may need enabling
4594 * stage must be lowest_disabled_stage here, if it's bigger success is returned above,
4595 * and stages below the lowest disabled stage can't be enabled(because they are enabled already).
4597 * Again stage Stage doesn't need to be dirtified here, it is handled below.
4600 for(i = Stage + 1; i < GL_LIMITS(texture_stages); i++) {
4601 if(This->updateStateBlock->textureState[i][WINED3DTSS_COLOROP] == WINED3DTOP_DISABLE) {
4602 break;
4604 TRACE("Additionally dirtifying stage %d due to enable\n", i);
4605 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(i, WINED3DTSS_COLOROP));
4607 This->stateBlock->lowest_disabled_stage = i;
4608 TRACE("New lowest disabled: %d\n", i);
4612 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, Type));
4614 return WINED3D_OK;
4617 static HRESULT WINAPI IWineD3DDeviceImpl_GetTextureStageState(IWineD3DDevice *iface, DWORD Stage, WINED3DTEXTURESTAGESTATETYPE Type, DWORD* pValue) {
4618 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4619 TRACE("(%p) : requesting Stage %d, Type %d getting %d\n", This, Stage, Type, This->updateStateBlock->textureState[Stage][Type]);
4620 *pValue = This->updateStateBlock->textureState[Stage][Type];
4621 return WINED3D_OK;
4624 /*****
4625 * Get / Set Texture
4626 *****/
4627 static HRESULT WINAPI IWineD3DDeviceImpl_SetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture* pTexture) {
4628 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4629 IWineD3DBaseTexture *oldTexture;
4631 TRACE("(%p) : Stage %#x, Texture %p\n", This, Stage, pTexture);
4633 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4634 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4637 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4638 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4639 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4642 oldTexture = This->updateStateBlock->textures[Stage];
4644 if(pTexture != NULL) {
4645 /* SetTexture isn't allowed on textures in WINED3DPOOL_SCRATCH;
4647 if(((IWineD3DTextureImpl*)pTexture)->resource.pool == WINED3DPOOL_SCRATCH) {
4648 WARN("(%p) Attempt to set scratch texture rejected\n", pTexture);
4649 return WINED3DERR_INVALIDCALL;
4651 This->stateBlock->textureDimensions[Stage] = IWineD3DBaseTexture_GetTextureDimensions(pTexture);
4654 TRACE("GL_LIMITS %d\n",GL_LIMITS(sampler_stages));
4655 TRACE("(%p) : oldtexture(%p)\n", This,oldTexture);
4657 This->updateStateBlock->changed.textures[Stage] = TRUE;
4658 TRACE("(%p) : setting new texture to %p\n", This, pTexture);
4659 This->updateStateBlock->textures[Stage] = pTexture;
4661 /* Handle recording of state blocks */
4662 if (This->isRecordingState) {
4663 TRACE("Recording... not performing anything\n");
4664 return WINED3D_OK;
4667 if(oldTexture == pTexture) {
4668 TRACE("App is setting the same texture again, nothing to do\n");
4669 return WINED3D_OK;
4672 /** NOTE: MSDN says that setTexture increases the reference count,
4673 * and that the application must set the texture back to null (or have a leaky application),
4674 * This means we should pass the refcount up to the parent
4675 *******************************/
4676 if (NULL != This->updateStateBlock->textures[Stage]) {
4677 IWineD3DBaseTextureImpl *new = (IWineD3DBaseTextureImpl *) This->updateStateBlock->textures[Stage];
4678 ULONG bindCount = InterlockedIncrement(&new->baseTexture.bindCount);
4680 IWineD3DBaseTexture_AddRef(This->updateStateBlock->textures[Stage]);
4681 if(oldTexture == NULL && Stage < MAX_TEXTURES) {
4682 /* The source arguments for color and alpha ops have different meanings when a NULL texture is bound,
4683 * so the COLOROP and ALPHAOP have to be dirtified.
4685 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4686 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4688 if(bindCount == 1) {
4689 new->baseTexture.sampler = Stage;
4691 /* More than one assignment? Doesn't matter, we only need one gl texture unit to use for uploading */
4695 if (NULL != oldTexture) {
4696 IWineD3DBaseTextureImpl *old = (IWineD3DBaseTextureImpl *) oldTexture;
4697 LONG bindCount = InterlockedDecrement(&old->baseTexture.bindCount);
4699 IWineD3DBaseTexture_Release(oldTexture);
4700 if(pTexture == NULL && Stage < MAX_TEXTURES) {
4701 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_COLOROP));
4702 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_TEXTURESTAGE(Stage, WINED3DTSS_ALPHAOP));
4705 if(bindCount && old->baseTexture.sampler == Stage) {
4706 int i;
4707 /* Have to do a search for the other sampler(s) where the texture is bound to
4708 * Shouldn't happen as long as apps bind a texture only to one stage
4710 TRACE("Searcing for other sampler / stage id where the texture is bound to\n");
4711 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
4712 if(This->updateStateBlock->textures[i] == oldTexture) {
4713 old->baseTexture.sampler = i;
4714 break;
4720 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(Stage));
4722 return WINED3D_OK;
4725 static HRESULT WINAPI IWineD3DDeviceImpl_GetTexture(IWineD3DDevice *iface, DWORD Stage, IWineD3DBaseTexture** ppTexture) {
4726 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4728 TRACE("(%p) : Stage %#x, ppTexture %p\n", This, Stage, ppTexture);
4730 if (Stage >= WINED3DVERTEXTEXTURESAMPLER0 && Stage <= WINED3DVERTEXTEXTURESAMPLER3) {
4731 Stage -= (WINED3DVERTEXTEXTURESAMPLER0 - MAX_FRAGMENT_SAMPLERS);
4734 if (Stage >= sizeof(This->stateBlock->textures)/sizeof(This->stateBlock->textures[0])) {
4735 ERR("Current stage overflows textures array (stage %d)\n", Stage);
4736 return WINED3D_OK; /* Windows accepts overflowing this array ... we do not. */
4739 *ppTexture=This->stateBlock->textures[Stage];
4740 if (*ppTexture)
4741 IWineD3DBaseTexture_AddRef(*ppTexture);
4743 TRACE("(%p) : Returning %p\n", This, *ppTexture);
4745 return WINED3D_OK;
4748 /*****
4749 * Get Back Buffer
4750 *****/
4751 static HRESULT WINAPI IWineD3DDeviceImpl_GetBackBuffer(IWineD3DDevice *iface, UINT iSwapChain, UINT BackBuffer, WINED3DBACKBUFFER_TYPE Type,
4752 IWineD3DSurface **ppBackBuffer) {
4753 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4754 IWineD3DSwapChain *swapChain;
4755 HRESULT hr;
4757 TRACE("(%p) : BackBuf %d Type %d SwapChain %d returning %p\n", This, BackBuffer, Type, iSwapChain, *ppBackBuffer);
4759 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4760 if (hr == WINED3D_OK) {
4761 hr = IWineD3DSwapChain_GetBackBuffer(swapChain, BackBuffer, Type, ppBackBuffer);
4762 IWineD3DSwapChain_Release(swapChain);
4763 } else {
4764 *ppBackBuffer = NULL;
4766 return hr;
4769 static HRESULT WINAPI IWineD3DDeviceImpl_GetDeviceCaps(IWineD3DDevice *iface, WINED3DCAPS* pCaps) {
4770 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4771 WARN("(%p) : stub, calling idirect3d for now\n", This);
4772 return IWineD3D_GetDeviceCaps(This->wineD3D, This->adapterNo, This->devType, pCaps);
4775 static HRESULT WINAPI IWineD3DDeviceImpl_GetDisplayMode(IWineD3DDevice *iface, UINT iSwapChain, WINED3DDISPLAYMODE* pMode) {
4776 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4777 IWineD3DSwapChain *swapChain;
4778 HRESULT hr;
4780 if(iSwapChain > 0) {
4781 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
4782 if (hr == WINED3D_OK) {
4783 hr = IWineD3DSwapChain_GetDisplayMode(swapChain, pMode);
4784 IWineD3DSwapChain_Release(swapChain);
4785 } else {
4786 FIXME("(%p) Error getting display mode\n", This);
4788 } else {
4789 /* Don't read the real display mode,
4790 but return the stored mode instead. X11 can't change the color
4791 depth, and some apps are pretty angry if they SetDisplayMode from
4792 24 to 16 bpp and find out that GetDisplayMode still returns 24 bpp
4794 Also don't relay to the swapchain because with ddraw it's possible
4795 that there isn't a swapchain at all */
4796 pMode->Width = This->ddraw_width;
4797 pMode->Height = This->ddraw_height;
4798 pMode->Format = This->ddraw_format;
4799 pMode->RefreshRate = 0;
4800 hr = WINED3D_OK;
4803 return hr;
4806 /*****
4807 * Stateblock related functions
4808 *****/
4810 static HRESULT WINAPI IWineD3DDeviceImpl_BeginStateBlock(IWineD3DDevice *iface) {
4811 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4812 IWineD3DStateBlockImpl *object;
4813 HRESULT temp_result;
4814 int i;
4816 TRACE("(%p)\n", This);
4818 if (This->isRecordingState) {
4819 return WINED3DERR_INVALIDCALL;
4822 object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DStateBlockImpl));
4823 if (NULL == object ) {
4824 FIXME("(%p)Error allocating memory for stateblock\n", This);
4825 return E_OUTOFMEMORY;
4827 TRACE("(%p) created object %p\n", This, object);
4828 object->wineD3DDevice= This;
4829 /** FIXME: object->parent = parent; **/
4830 object->parent = NULL;
4831 object->blockType = WINED3DSBT_RECORDED;
4832 object->ref = 1;
4833 object->lpVtbl = &IWineD3DStateBlock_Vtbl;
4835 for(i = 0; i < LIGHTMAP_SIZE; i++) {
4836 list_init(&object->lightMap[i]);
4839 temp_result = allocate_shader_constants(object);
4840 if (WINED3D_OK != temp_result)
4841 return temp_result;
4843 IWineD3DStateBlock_Release((IWineD3DStateBlock*)This->updateStateBlock);
4844 This->updateStateBlock = object;
4845 This->isRecordingState = TRUE;
4847 TRACE("(%p) recording stateblock %p\n",This , object);
4848 return WINED3D_OK;
4851 static HRESULT WINAPI IWineD3DDeviceImpl_EndStateBlock(IWineD3DDevice *iface, IWineD3DStateBlock** ppStateBlock) {
4852 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4853 unsigned int i, j;
4854 IWineD3DStateBlockImpl *object = This->updateStateBlock;
4856 if (!This->isRecordingState) {
4857 FIXME("(%p) not recording! returning error\n", This);
4858 *ppStateBlock = NULL;
4859 return WINED3DERR_INVALIDCALL;
4862 for(i = 1; i <= WINEHIGHEST_RENDER_STATE; i++) {
4863 if(object->changed.renderState[i]) {
4864 object->contained_render_states[object->num_contained_render_states] = i;
4865 object->num_contained_render_states++;
4868 for(i = 1; i <= HIGHEST_TRANSFORMSTATE; i++) {
4869 if(object->changed.transform[i]) {
4870 object->contained_transform_states[object->num_contained_transform_states] = i;
4871 object->num_contained_transform_states++;
4874 for(i = 0; i < GL_LIMITS(vshader_constantsF); i++) {
4875 if(object->changed.vertexShaderConstantsF[i]) {
4876 object->contained_vs_consts_f[object->num_contained_vs_consts_f] = i;
4877 object->num_contained_vs_consts_f++;
4880 for(i = 0; i < MAX_CONST_I; i++) {
4881 if(object->changed.vertexShaderConstantsI[i]) {
4882 object->contained_vs_consts_i[object->num_contained_vs_consts_i] = i;
4883 object->num_contained_vs_consts_i++;
4886 for(i = 0; i < MAX_CONST_B; i++) {
4887 if(object->changed.vertexShaderConstantsB[i]) {
4888 object->contained_vs_consts_b[object->num_contained_vs_consts_b] = i;
4889 object->num_contained_vs_consts_b++;
4892 for(i = 0; i < MAX_CONST_I; i++) {
4893 if(object->changed.pixelShaderConstantsI[i]) {
4894 object->contained_ps_consts_i[object->num_contained_ps_consts_i] = i;
4895 object->num_contained_ps_consts_i++;
4898 for(i = 0; i < MAX_CONST_B; i++) {
4899 if(object->changed.pixelShaderConstantsB[i]) {
4900 object->contained_ps_consts_b[object->num_contained_ps_consts_b] = i;
4901 object->num_contained_ps_consts_b++;
4904 for(i = 0; i < MAX_TEXTURES; i++) {
4905 for(j = 1; j <= WINED3D_HIGHEST_TEXTURE_STATE; j++) {
4906 if(object->changed.textureState[i][j]) {
4907 object->contained_tss_states[object->num_contained_tss_states].stage = i;
4908 object->contained_tss_states[object->num_contained_tss_states].state = j;
4909 object->num_contained_tss_states++;
4913 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++){
4914 for (j = 1; j < WINED3D_HIGHEST_SAMPLER_STATE; j++) {
4915 if(object->changed.samplerState[i][j]) {
4916 object->contained_sampler_states[object->num_contained_sampler_states].stage = i;
4917 object->contained_sampler_states[object->num_contained_sampler_states].state = j;
4918 object->num_contained_sampler_states++;
4923 *ppStateBlock = (IWineD3DStateBlock*) object;
4924 This->isRecordingState = FALSE;
4925 This->updateStateBlock = This->stateBlock;
4926 IWineD3DStateBlock_AddRef((IWineD3DStateBlock*)This->updateStateBlock);
4927 /* IWineD3DStateBlock_AddRef(*ppStateBlock); don't need to do this, since we should really just release UpdateStateBlock first */
4928 TRACE("(%p) returning token (ptr to stateblock) of %p\n", This, *ppStateBlock);
4929 return WINED3D_OK;
4932 /*****
4933 * Scene related functions
4934 *****/
4935 static HRESULT WINAPI IWineD3DDeviceImpl_BeginScene(IWineD3DDevice *iface) {
4936 /* At the moment we have no need for any functionality at the beginning
4937 of a scene */
4938 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4939 TRACE("(%p)\n", This);
4941 if(This->inScene) {
4942 TRACE("Already in Scene, returning WINED3DERR_INVALIDCALL\n");
4943 return WINED3DERR_INVALIDCALL;
4945 This->inScene = TRUE;
4946 return WINED3D_OK;
4949 static HRESULT WINAPI IWineD3DDeviceImpl_EndScene(IWineD3DDevice *iface) {
4950 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4951 TRACE("(%p)\n", This);
4953 if(!This->inScene) {
4954 TRACE("Not in scene, returning WINED3DERR_INVALIDCALL\n");
4955 return WINED3DERR_INVALIDCALL;
4958 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
4959 /* We only have to do this if we need to read the, swapbuffers performs a flush for us */
4960 glFlush();
4961 /* No checkGLcall here to avoid locking the lock just for checking a call that hardly ever
4962 * fails
4965 This->inScene = FALSE;
4966 return WINED3D_OK;
4969 static HRESULT WINAPI IWineD3DDeviceImpl_Present(IWineD3DDevice *iface,
4970 CONST RECT* pSourceRect, CONST RECT* pDestRect,
4971 HWND hDestWindowOverride, CONST RGNDATA* pDirtyRegion) {
4972 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
4973 IWineD3DSwapChain *swapChain = NULL;
4974 int i;
4975 int swapchains = IWineD3DDeviceImpl_GetNumberOfSwapChains(iface);
4977 TRACE("(%p) Presenting the frame\n", This);
4979 for(i = 0 ; i < swapchains ; i ++) {
4981 IWineD3DDeviceImpl_GetSwapChain(iface, i, &swapChain);
4982 TRACE("presentinng chain %d, %p\n", i, swapChain);
4983 IWineD3DSwapChain_Present(swapChain, pSourceRect, pDestRect, hDestWindowOverride, pDirtyRegion, 0);
4984 IWineD3DSwapChain_Release(swapChain);
4987 return WINED3D_OK;
4990 /* Not called from the VTable (internal subroutine) */
4991 HRESULT IWineD3DDeviceImpl_ClearSurface(IWineD3DDeviceImpl *This, IWineD3DSurfaceImpl *target, DWORD Count,
4992 CONST WINED3DRECT* pRects, DWORD Flags, WINED3DCOLOR Color,
4993 float Z, DWORD Stencil) {
4994 GLbitfield glMask = 0;
4995 unsigned int i;
4996 WINED3DRECT curRect;
4997 RECT vp_rect;
4998 WINED3DVIEWPORT *vp = &This->stateBlock->viewport;
4999 UINT drawable_width, drawable_height;
5000 IWineD3DSurfaceImpl *depth_stencil = (IWineD3DSurfaceImpl *) This->stencilBufferTarget;
5001 IWineD3DSwapChainImpl *swapchain = NULL;
5003 /* When we're clearing parts of the drawable, make sure that the target surface is well up to date in the
5004 * drawable. After the clear we'll mark the drawable up to date, so we have to make sure that this is true
5005 * for the cleared parts, and the untouched parts.
5007 * If we're clearing the whole target there is no need to copy it into the drawable, it will be overwritten
5008 * anyway. If we're not clearing the color buffer we don't have to copy either since we're not going to set
5009 * the drawable up to date. We have to check all settings that limit the clear area though. Do not bother
5010 * checking all this if the dest surface is in the drawable anyway.
5012 if((Flags & WINED3DCLEAR_TARGET) && !(target->Flags & SFLAG_INDRAWABLE)) {
5013 while(1) {
5014 if(vp->X != 0 || vp->Y != 0 ||
5015 vp->Width < target->currentDesc.Width || vp->Height < target->currentDesc.Height) {
5016 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5017 break;
5019 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5020 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5021 This->stateBlock->scissorRect.right < target->currentDesc.Width ||
5022 This->stateBlock->scissorRect.bottom < target->currentDesc.Height)) {
5023 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5024 break;
5026 if(Count > 0 && pRects && (
5027 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5028 pRects[0].x2 < target->currentDesc.Width ||
5029 pRects[0].y2 < target->currentDesc.Height)) {
5030 IWineD3DSurface_LoadLocation((IWineD3DSurface *) target, SFLAG_INDRAWABLE, NULL);
5031 break;
5033 break;
5037 target->get_drawable_size(target, &drawable_width, &drawable_height);
5039 ActivateContext(This, (IWineD3DSurface *) target, CTXUSAGE_CLEAR);
5040 ENTER_GL();
5042 /* Only set the values up once, as they are not changing */
5043 if (Flags & WINED3DCLEAR_STENCIL) {
5044 glClearStencil(Stencil);
5045 checkGLcall("glClearStencil");
5046 glMask = glMask | GL_STENCIL_BUFFER_BIT;
5047 glStencilMask(0xFFFFFFFF);
5050 if (Flags & WINED3DCLEAR_ZBUFFER) {
5051 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5052 glDepthMask(GL_TRUE);
5053 glClearDepth(Z);
5054 checkGLcall("glClearDepth");
5055 glMask = glMask | GL_DEPTH_BUFFER_BIT;
5056 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZWRITEENABLE));
5058 if (vp->X != 0 || vp->Y != 0 ||
5059 vp->Width < depth_stencil->currentDesc.Width || vp->Height < depth_stencil->currentDesc.Height) {
5060 surface_load_ds_location(This->stencilBufferTarget, location);
5062 else if (This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE] && (
5063 This->stateBlock->scissorRect.left > 0 || This->stateBlock->scissorRect.top > 0 ||
5064 This->stateBlock->scissorRect.right < depth_stencil->currentDesc.Width ||
5065 This->stateBlock->scissorRect.bottom < depth_stencil->currentDesc.Height)) {
5066 surface_load_ds_location(This->stencilBufferTarget, location);
5068 else if (Count > 0 && pRects && (
5069 pRects[0].x1 > 0 || pRects[0].y1 > 0 ||
5070 pRects[0].x2 < depth_stencil->currentDesc.Width ||
5071 pRects[0].y2 < depth_stencil->currentDesc.Height)) {
5072 surface_load_ds_location(This->stencilBufferTarget, location);
5076 if (Flags & WINED3DCLEAR_TARGET) {
5077 TRACE("Clearing screen with glClear to color %x\n", Color);
5078 glClearColor(D3DCOLOR_R(Color),
5079 D3DCOLOR_G(Color),
5080 D3DCOLOR_B(Color),
5081 D3DCOLOR_A(Color));
5082 checkGLcall("glClearColor");
5084 /* Clear ALL colors! */
5085 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
5086 glMask = glMask | GL_COLOR_BUFFER_BIT;
5089 vp_rect.left = vp->X;
5090 vp_rect.top = vp->Y;
5091 vp_rect.right = vp->X + vp->Width;
5092 vp_rect.bottom = vp->Y + vp->Height;
5093 if (!(Count > 0 && pRects)) {
5094 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5095 IntersectRect(&vp_rect, &vp_rect, &This->stateBlock->scissorRect);
5097 if(This->render_offscreen) {
5098 glScissor(vp_rect.left, vp_rect.top,
5099 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5100 } else {
5101 glScissor(vp_rect.left, drawable_height - vp_rect.bottom,
5102 vp_rect.right - vp_rect.left, vp_rect.bottom - vp_rect.top);
5104 checkGLcall("glScissor");
5105 glClear(glMask);
5106 checkGLcall("glClear");
5107 } else {
5108 /* Now process each rect in turn */
5109 for (i = 0; i < Count; i++) {
5110 /* Note gl uses lower left, width/height */
5111 IntersectRect((RECT *) &curRect, &vp_rect, (RECT *) &pRects[i]);
5112 if(This->stateBlock->renderState[WINED3DRS_SCISSORTESTENABLE]) {
5113 IntersectRect((RECT *) &curRect, (RECT *) &curRect, &This->stateBlock->scissorRect);
5115 TRACE("(%p) Rect=(%d,%d)->(%d,%d) glRect=(%d,%d), len=%d, hei=%d\n", This,
5116 pRects[i].x1, pRects[i].y1, pRects[i].x2, pRects[i].y2,
5117 curRect.x1, (target->currentDesc.Height - curRect.y2),
5118 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5120 /* Tests show that rectangles where x1 > x2 or y1 > y2 are ignored silently.
5121 * The rectangle is not cleared, no error is returned, but further rectanlges are
5122 * still cleared if they are valid
5124 if(curRect.x1 > curRect.x2 || curRect.y1 > curRect.y2) {
5125 TRACE("Rectangle with negative dimensions, ignoring\n");
5126 continue;
5129 if(This->render_offscreen) {
5130 glScissor(curRect.x1, curRect.y1,
5131 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5132 } else {
5133 glScissor(curRect.x1, drawable_height - curRect.y2,
5134 curRect.x2 - curRect.x1, curRect.y2 - curRect.y1);
5136 checkGLcall("glScissor");
5138 glClear(glMask);
5139 checkGLcall("glClear");
5143 /* Restore the old values (why..?) */
5144 if (Flags & WINED3DCLEAR_STENCIL) {
5145 glStencilMask(This->stateBlock->renderState[WINED3DRS_STENCILWRITEMASK]);
5147 if (Flags & WINED3DCLEAR_TARGET) {
5148 DWORD mask = This->stateBlock->renderState[WINED3DRS_COLORWRITEENABLE];
5149 glColorMask(mask & WINED3DCOLORWRITEENABLE_RED ? GL_TRUE : GL_FALSE,
5150 mask & WINED3DCOLORWRITEENABLE_GREEN ? GL_TRUE : GL_FALSE,
5151 mask & WINED3DCOLORWRITEENABLE_BLUE ? GL_TRUE : GL_FALSE,
5152 mask & WINED3DCOLORWRITEENABLE_ALPHA ? GL_TRUE : GL_FALSE);
5154 /* Dirtify the target surface for now. If the surface is locked regularly, and an up to date sysmem copy exists,
5155 * it is most likely more efficient to perform a clear on the sysmem copy too instead of downloading it
5157 IWineD3DSurface_ModifyLocation(This->lastActiveRenderTarget, SFLAG_INDRAWABLE, TRUE);
5159 if (Flags & WINED3DCLEAR_ZBUFFER) {
5160 /* Note that WINED3DCLEAR_ZBUFFER implies a depth stencil exists on the device */
5161 DWORD location = This->render_offscreen ? SFLAG_DS_OFFSCREEN : SFLAG_DS_ONSCREEN;
5162 surface_modify_ds_location(This->stencilBufferTarget, location);
5165 LEAVE_GL();
5167 IWineD3DSurface_GetContainer( (IWineD3DSurface *) target, &IID_IWineD3DSwapChain, (void **)&swapchain);
5168 if (swapchain) {
5169 if (target == (IWineD3DSurfaceImpl*) swapchain->frontBuffer) {
5170 glFlush();
5172 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
5175 return WINED3D_OK;
5178 static HRESULT WINAPI IWineD3DDeviceImpl_Clear(IWineD3DDevice *iface, DWORD Count, CONST WINED3DRECT* pRects,
5179 DWORD Flags, WINED3DCOLOR Color, float Z, DWORD Stencil) {
5180 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5181 IWineD3DSurfaceImpl *target = (IWineD3DSurfaceImpl *)This->render_targets[0];
5183 TRACE("(%p) Count (%d), pRects (%p), Flags (%x), Color (0x%08x), Z (%f), Stencil (%d)\n", This,
5184 Count, pRects, Flags, Color, Z, Stencil);
5186 if(Flags & (WINED3DCLEAR_ZBUFFER | WINED3DCLEAR_STENCIL) && This->stencilBufferTarget == NULL) {
5187 WARN("Clearing depth and/or stencil without a depth stencil buffer attached, returning WINED3DERR_INVALIDCALL\n");
5188 /* TODO: What about depth stencil buffers without stencil bits? */
5189 return WINED3DERR_INVALIDCALL;
5192 return IWineD3DDeviceImpl_ClearSurface(This, target, Count, pRects, Flags, Color, Z, Stencil);
5195 /*****
5196 * Drawing functions
5197 *****/
5198 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitive(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT StartVertex,
5199 UINT PrimitiveCount) {
5201 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5203 TRACE("(%p) : Type=(%d,%s), Start=%d, Count=%d\n", This, PrimitiveType,
5204 debug_d3dprimitivetype(PrimitiveType),
5205 StartVertex, PrimitiveCount);
5207 if(!This->stateBlock->vertexDecl) {
5208 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5209 return WINED3DERR_INVALIDCALL;
5212 /* The index buffer is not needed here, but restore it, otherwise it is hell to keep track of */
5213 if(This->stateBlock->streamIsUP) {
5214 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5215 This->stateBlock->streamIsUP = FALSE;
5218 if(This->stateBlock->loadBaseVertexIndex != 0) {
5219 This->stateBlock->loadBaseVertexIndex = 0;
5220 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5222 /* Account for the loading offset due to index buffers. Instead of reloading all sources correct it with the startvertex parameter */
5223 drawPrimitive(iface, PrimitiveType, PrimitiveCount, StartVertex, 0/* NumVertices */, -1 /* indxStart */,
5224 0 /* indxSize */, NULL /* indxData */, 0 /* minIndex */);
5225 return WINED3D_OK;
5228 /* TODO: baseVIndex needs to be provided from This->stateBlock->baseVertexIndex when called from d3d8 */
5229 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitive(IWineD3DDevice *iface,
5230 WINED3DPRIMITIVETYPE PrimitiveType,
5231 UINT minIndex, UINT NumVertices, UINT startIndex, UINT primCount) {
5233 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5234 UINT idxStride = 2;
5235 IWineD3DIndexBuffer *pIB;
5236 WINED3DINDEXBUFFER_DESC IdxBufDsc;
5237 GLuint vbo;
5239 pIB = This->stateBlock->pIndexData;
5240 if (!pIB) {
5241 /* D3D9 returns D3DERR_INVALIDCALL when DrawIndexedPrimitive is called
5242 * without an index buffer set. (The first time at least...)
5243 * D3D8 simply dies, but I doubt it can do much harm to return
5244 * D3DERR_INVALIDCALL there as well. */
5245 ERR("(%p) : Called without a valid index buffer set, returning WINED3DERR_INVALIDCALL\n", This);
5246 return WINED3DERR_INVALIDCALL;
5249 if(!This->stateBlock->vertexDecl) {
5250 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5251 return WINED3DERR_INVALIDCALL;
5254 if(This->stateBlock->streamIsUP) {
5255 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5256 This->stateBlock->streamIsUP = FALSE;
5258 vbo = ((IWineD3DIndexBufferImpl *) pIB)->vbo;
5260 TRACE("(%p) : Type=(%d,%s), min=%d, CountV=%d, startIdx=%d, countP=%d\n", This,
5261 PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5262 minIndex, NumVertices, startIndex, primCount);
5264 IWineD3DIndexBuffer_GetDesc(pIB, &IdxBufDsc);
5265 if (IdxBufDsc.Format == WINED3DFMT_INDEX16) {
5266 idxStride = 2;
5267 } else {
5268 idxStride = 4;
5271 if(This->stateBlock->loadBaseVertexIndex != This->stateBlock->baseVertexIndex) {
5272 This->stateBlock->loadBaseVertexIndex = This->stateBlock->baseVertexIndex;
5273 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5276 drawPrimitive(iface, PrimitiveType, primCount, 0, NumVertices, startIndex,
5277 idxStride, vbo ? NULL : ((IWineD3DIndexBufferImpl *) pIB)->resource.allocatedMemory, minIndex);
5279 return WINED3D_OK;
5282 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5283 UINT PrimitiveCount, CONST void* pVertexStreamZeroData,
5284 UINT VertexStreamZeroStride) {
5285 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5286 IWineD3DVertexBuffer *vb;
5288 TRACE("(%p) : Type=(%d,%s), pCount=%d, pVtxData=%p, Stride=%d\n", This, PrimitiveType,
5289 debug_d3dprimitivetype(PrimitiveType),
5290 PrimitiveCount, pVertexStreamZeroData, VertexStreamZeroStride);
5292 if(!This->stateBlock->vertexDecl) {
5293 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5294 return WINED3DERR_INVALIDCALL;
5297 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5298 vb = This->stateBlock->streamSource[0];
5299 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5300 if(vb) IWineD3DVertexBuffer_Release(vb);
5301 This->stateBlock->streamOffset[0] = 0;
5302 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5303 This->stateBlock->streamIsUP = TRUE;
5304 This->stateBlock->loadBaseVertexIndex = 0;
5306 /* TODO: Only mark dirty if drawing from a different UP address */
5307 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_STREAMSRC);
5309 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* start vertex */, 0 /* NumVertices */,
5310 0 /* indxStart*/, 0 /* indxSize*/, NULL /* indxData */, 0 /* indxMin */);
5312 /* MSDN specifies stream zero settings must be set to NULL */
5313 This->stateBlock->streamStride[0] = 0;
5314 This->stateBlock->streamSource[0] = NULL;
5316 /* stream zero settings set to null at end, as per the msdn. No need to mark dirty here, the app has to set
5317 * the new stream sources or use UP drawing again
5319 return WINED3D_OK;
5322 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveUP(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType,
5323 UINT MinVertexIndex, UINT NumVertices,
5324 UINT PrimitiveCount, CONST void* pIndexData,
5325 WINED3DFORMAT IndexDataFormat,CONST void* pVertexStreamZeroData,
5326 UINT VertexStreamZeroStride) {
5327 int idxStride;
5328 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5329 IWineD3DVertexBuffer *vb;
5330 IWineD3DIndexBuffer *ib;
5332 TRACE("(%p) : Type=(%d,%s), MinVtxIdx=%d, NumVIdx=%d, PCount=%d, pidxdata=%p, IdxFmt=%d, pVtxdata=%p, stride=%d\n",
5333 This, PrimitiveType, debug_d3dprimitivetype(PrimitiveType),
5334 MinVertexIndex, NumVertices, PrimitiveCount, pIndexData,
5335 IndexDataFormat, pVertexStreamZeroData, VertexStreamZeroStride);
5337 if(!This->stateBlock->vertexDecl) {
5338 WARN("(%p) : Called without a valid vertex declaration set\n", This);
5339 return WINED3DERR_INVALIDCALL;
5342 if (IndexDataFormat == WINED3DFMT_INDEX16) {
5343 idxStride = 2;
5344 } else {
5345 idxStride = 4;
5348 /* Note in the following, it's not this type, but that's the purpose of streamIsUP */
5349 vb = This->stateBlock->streamSource[0];
5350 This->stateBlock->streamSource[0] = (IWineD3DVertexBuffer *)pVertexStreamZeroData;
5351 if(vb) IWineD3DVertexBuffer_Release(vb);
5352 This->stateBlock->streamIsUP = TRUE;
5353 This->stateBlock->streamOffset[0] = 0;
5354 This->stateBlock->streamStride[0] = VertexStreamZeroStride;
5356 /* Set to 0 as per msdn. Do it now due to the stream source loading during drawPrimitive */
5357 This->stateBlock->baseVertexIndex = 0;
5358 This->stateBlock->loadBaseVertexIndex = 0;
5359 /* Mark the state dirty until we have nicer tracking of the stream source pointers */
5360 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5361 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5363 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* vertexStart */, NumVertices, 0 /* indxStart */, idxStride, pIndexData, MinVertexIndex);
5365 /* MSDN specifies stream zero settings and index buffer must be set to NULL */
5366 This->stateBlock->streamSource[0] = NULL;
5367 This->stateBlock->streamStride[0] = 0;
5368 ib = This->stateBlock->pIndexData;
5369 if(ib) {
5370 IWineD3DIndexBuffer_Release(ib);
5371 This->stateBlock->pIndexData = NULL;
5373 /* No need to mark the stream source state dirty here. Either the app calls UP drawing again, or it has to call
5374 * SetStreamSource to specify a vertex buffer
5377 return WINED3D_OK;
5380 static HRESULT WINAPI IWineD3DDeviceImpl_DrawPrimitiveStrided (IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData) {
5381 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5383 /* Mark the state dirty until we have nicer tracking
5384 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5385 * that value.
5387 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5388 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5389 This->stateBlock->baseVertexIndex = 0;
5390 This->up_strided = DrawPrimStrideData;
5391 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0, 0, 0, 0, NULL, 0);
5392 This->up_strided = NULL;
5393 return WINED3D_OK;
5396 static HRESULT WINAPI IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided(IWineD3DDevice *iface, WINED3DPRIMITIVETYPE PrimitiveType, UINT PrimitiveCount, WineDirect3DVertexStridedData *DrawPrimStrideData, UINT NumVertices, CONST void *pIndexData, WINED3DFORMAT IndexDataFormat) {
5397 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5398 DWORD idxSize = (IndexDataFormat == WINED3DFMT_INDEX32 ? 4 : 2);
5400 /* Mark the state dirty until we have nicer tracking
5401 * its fine to change baseVertexIndex because that call is only called by ddraw which does not need
5402 * that value.
5404 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VDECL);
5405 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_INDEXBUFFER);
5406 This->stateBlock->streamIsUP = TRUE;
5407 This->stateBlock->baseVertexIndex = 0;
5408 This->up_strided = DrawPrimStrideData;
5409 drawPrimitive(iface, PrimitiveType, PrimitiveCount, 0 /* startvertexidx */, 0 /* numindices */, 0 /* startidx */, idxSize, pIndexData, 0 /* minindex */);
5410 This->up_strided = NULL;
5411 return WINED3D_OK;
5414 static HRESULT IWineD3DDeviceImpl_UpdateVolume(IWineD3DDevice *iface, IWineD3DVolume *pSourceVolume, IWineD3DVolume *pDestinationVolume) {
5415 /* This is a helper function for UpdateTexture, there is no public UpdateVolume method in d3d. Since it's
5416 * not callable by the app directly no parameter validation checks are needed here.
5418 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5419 WINED3DLOCKED_BOX src;
5420 WINED3DLOCKED_BOX dst;
5421 HRESULT hr;
5422 TRACE("(%p)->(%p, %p)\n", This, pSourceVolume, pDestinationVolume);
5424 /* TODO: Implement direct loading into the gl volume instead of using memcpy and
5425 * dirtification to improve loading performance.
5427 hr = IWineD3DVolume_LockBox(pSourceVolume, &src, NULL, WINED3DLOCK_READONLY);
5428 if(FAILED(hr)) return hr;
5429 hr = IWineD3DVolume_LockBox(pDestinationVolume, &dst, NULL, WINED3DLOCK_DISCARD);
5430 if(FAILED(hr)) {
5431 IWineD3DVolume_UnlockBox(pSourceVolume);
5432 return hr;
5435 memcpy(dst.pBits, src.pBits, ((IWineD3DVolumeImpl *) pDestinationVolume)->resource.size);
5437 hr = IWineD3DVolume_UnlockBox(pDestinationVolume);
5438 if(FAILED(hr)) {
5439 IWineD3DVolume_UnlockBox(pSourceVolume);
5440 } else {
5441 hr = IWineD3DVolume_UnlockBox(pSourceVolume);
5443 return hr;
5446 /* Yet another way to update a texture, some apps use this to load default textures instead of using surface/texture lock/unlock */
5447 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateTexture (IWineD3DDevice *iface, IWineD3DBaseTexture *pSourceTexture, IWineD3DBaseTexture *pDestinationTexture){
5448 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5449 HRESULT hr = WINED3D_OK;
5450 WINED3DRESOURCETYPE sourceType;
5451 WINED3DRESOURCETYPE destinationType;
5452 int i ,levels;
5454 /* TODO: think about moving the code into IWineD3DBaseTexture */
5456 TRACE("(%p) Source %p Destination %p\n", This, pSourceTexture, pDestinationTexture);
5458 /* verify that the source and destination textures aren't NULL */
5459 if (NULL == pSourceTexture || NULL == pDestinationTexture) {
5460 WARN("(%p) : source (%p) and destination (%p) textures must not be NULL, returning WINED3DERR_INVALIDCALL\n",
5461 This, pSourceTexture, pDestinationTexture);
5462 hr = WINED3DERR_INVALIDCALL;
5465 if (pSourceTexture == pDestinationTexture) {
5466 WARN("(%p) : source (%p) and destination (%p) textures must be different, returning WINED3DERR_INVALIDCALL\n",
5467 This, pSourceTexture, pDestinationTexture);
5468 hr = WINED3DERR_INVALIDCALL;
5470 /* Verify that the source and destination textures are the same type */
5471 sourceType = IWineD3DBaseTexture_GetType(pSourceTexture);
5472 destinationType = IWineD3DBaseTexture_GetType(pDestinationTexture);
5474 if (sourceType != destinationType) {
5475 WARN("(%p) Sorce and destination types must match, returning WINED3DERR_INVALIDCALL\n",
5476 This);
5477 hr = WINED3DERR_INVALIDCALL;
5480 /* check that both textures have the identical numbers of levels */
5481 if (IWineD3DBaseTexture_GetLevelCount(pDestinationTexture) != IWineD3DBaseTexture_GetLevelCount(pSourceTexture)) {
5482 WARN("(%p) : source (%p) and destination (%p) textures must have identical numbers of levels, returning WINED3DERR_INVALIDCALL\n", This, pSourceTexture, pDestinationTexture);
5483 hr = WINED3DERR_INVALIDCALL;
5486 if (WINED3D_OK == hr) {
5488 /* Make sure that the destination texture is loaded */
5489 IWineD3DBaseTexture_PreLoad(pDestinationTexture);
5491 /* Update every surface level of the texture */
5492 levels = IWineD3DBaseTexture_GetLevelCount(pDestinationTexture);
5494 switch (sourceType) {
5495 case WINED3DRTYPE_TEXTURE:
5497 IWineD3DSurface *srcSurface;
5498 IWineD3DSurface *destSurface;
5500 for (i = 0 ; i < levels ; ++i) {
5501 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pSourceTexture, i, &srcSurface);
5502 IWineD3DTexture_GetSurfaceLevel((IWineD3DTexture *)pDestinationTexture, i, &destSurface);
5503 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5504 IWineD3DSurface_Release(srcSurface);
5505 IWineD3DSurface_Release(destSurface);
5506 if (WINED3D_OK != hr) {
5507 WARN("(%p) : Call to update surface failed\n", This);
5508 return hr;
5512 break;
5513 case WINED3DRTYPE_CUBETEXTURE:
5515 IWineD3DSurface *srcSurface;
5516 IWineD3DSurface *destSurface;
5517 WINED3DCUBEMAP_FACES faceType;
5519 for (i = 0 ; i < levels ; ++i) {
5520 /* Update each cube face */
5521 for (faceType = WINED3DCUBEMAP_FACE_POSITIVE_X; faceType <= WINED3DCUBEMAP_FACE_NEGATIVE_Z; ++faceType){
5522 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pSourceTexture, faceType, i, &srcSurface);
5523 if (WINED3D_OK != hr) {
5524 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5525 } else {
5526 TRACE("Got srcSurface %p\n", srcSurface);
5528 hr = IWineD3DCubeTexture_GetCubeMapSurface((IWineD3DCubeTexture *)pDestinationTexture, faceType, i, &destSurface);
5529 if (WINED3D_OK != hr) {
5530 FIXME("(%p) : Failed to get src cube surface facetype %d, level %d\n", This, faceType, i);
5531 } else {
5532 TRACE("Got desrSurface %p\n", destSurface);
5534 hr = IWineD3DDevice_UpdateSurface(iface, srcSurface, NULL, destSurface, NULL);
5535 IWineD3DSurface_Release(srcSurface);
5536 IWineD3DSurface_Release(destSurface);
5537 if (WINED3D_OK != hr) {
5538 WARN("(%p) : Call to update surface failed\n", This);
5539 return hr;
5544 break;
5546 case WINED3DRTYPE_VOLUMETEXTURE:
5548 IWineD3DVolume *srcVolume = NULL;
5549 IWineD3DVolume *destVolume = NULL;
5551 for (i = 0 ; i < levels ; ++i) {
5552 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pSourceTexture, i, &srcVolume);
5553 IWineD3DVolumeTexture_GetVolumeLevel((IWineD3DVolumeTexture *)pDestinationTexture, i, &destVolume);
5554 hr = IWineD3DDeviceImpl_UpdateVolume(iface, srcVolume, destVolume);
5555 IWineD3DVolume_Release(srcVolume);
5556 IWineD3DVolume_Release(destVolume);
5557 if (WINED3D_OK != hr) {
5558 WARN("(%p) : Call to update volume failed\n", This);
5559 return hr;
5563 break;
5565 default:
5566 FIXME("(%p) : Unsupported source and destination type\n", This);
5567 hr = WINED3DERR_INVALIDCALL;
5571 return hr;
5574 static HRESULT WINAPI IWineD3DDeviceImpl_GetFrontBufferData(IWineD3DDevice *iface,UINT iSwapChain, IWineD3DSurface *pDestSurface) {
5575 IWineD3DSwapChain *swapChain;
5576 HRESULT hr;
5577 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5578 if(hr == WINED3D_OK) {
5579 hr = IWineD3DSwapChain_GetFrontBufferData(swapChain, pDestSurface);
5580 IWineD3DSwapChain_Release(swapChain);
5582 return hr;
5585 static HRESULT WINAPI IWineD3DDeviceImpl_ValidateDevice(IWineD3DDevice *iface, DWORD* pNumPasses) {
5586 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5587 IWineD3DBaseTextureImpl *texture;
5588 const GlPixelFormatDesc *gl_info;
5589 DWORD i;
5591 TRACE("(%p) : %p\n", This, pNumPasses);
5593 for(i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5594 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] == WINED3DTEXF_NONE) {
5595 WARN("Sampler state %u has minfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5596 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5598 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] == WINED3DTEXF_NONE) {
5599 WARN("Sampler state %u has magfilter D3DTEXF_NONE, returning D3DERR_UNSUPPORTEDTEXTUREFILTER\n", i);
5600 return WINED3DERR_UNSUPPORTEDTEXTUREFILTER;
5603 texture = (IWineD3DBaseTextureImpl *) This->stateBlock->textures[i];
5604 if(!texture) continue;
5605 getFormatDescEntry(texture->resource.format, &GLINFO_LOCATION, &gl_info);
5606 if(gl_info->Flags & WINED3DFMT_FLAG_FILTERING) continue;
5608 if(This->stateBlock->samplerState[i][WINED3DSAMP_MAGFILTER] != WINED3DTEXF_POINT) {
5609 WARN("Non-filterable texture and mag filter enabled on samper %u, returning E_FAIL\n", i);
5610 return E_FAIL;
5612 if(This->stateBlock->samplerState[i][WINED3DSAMP_MINFILTER] != WINED3DTEXF_POINT) {
5613 WARN("Non-filterable texture and min filter enabled on samper %u, returning E_FAIL\n", i);
5614 return E_FAIL;
5616 if(This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_NONE &&
5617 This->stateBlock->samplerState[i][WINED3DSAMP_MIPFILTER] != WINED3DTEXF_POINT /* sic! */) {
5618 WARN("Non-filterable texture and mip filter enabled on samper %u, returning E_FAIL\n", i);
5619 return E_FAIL;
5623 /* return a sensible default */
5624 *pNumPasses = 1;
5626 TRACE("returning D3D_OK\n");
5627 return WINED3D_OK;
5630 static void dirtify_p8_texture_samplers(IWineD3DDeviceImpl *device)
5632 int i;
5634 for (i = 0; i < MAX_COMBINED_SAMPLERS; i++) {
5635 IWineD3DBaseTextureImpl *texture = (IWineD3DBaseTextureImpl*)device->stateBlock->textures[i];
5636 if (texture && (texture->resource.format == WINED3DFMT_P8 || texture->resource.format == WINED3DFMT_A8P8)) {
5637 IWineD3DDeviceImpl_MarkStateDirty(device, STATE_SAMPLER(i));
5642 static HRESULT WINAPI IWineD3DDeviceImpl_SetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, CONST PALETTEENTRY* pEntries) {
5643 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5644 int j;
5645 UINT NewSize;
5646 PALETTEENTRY **palettes;
5648 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5650 if (PaletteNumber >= MAX_PALETTES) {
5651 ERR("(%p) : (%u) Out of range 0-%u, returning Invalid Call\n", This, PaletteNumber, MAX_PALETTES);
5652 return WINED3DERR_INVALIDCALL;
5655 if (PaletteNumber >= This->NumberOfPalettes) {
5656 NewSize = This->NumberOfPalettes;
5657 do {
5658 NewSize *= 2;
5659 } while(PaletteNumber >= NewSize);
5660 palettes = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, This->palettes, sizeof(PALETTEENTRY*) * NewSize);
5661 if (!palettes) {
5662 ERR("Out of memory!\n");
5663 return E_OUTOFMEMORY;
5665 This->palettes = palettes;
5666 This->NumberOfPalettes = NewSize;
5669 if (!This->palettes[PaletteNumber]) {
5670 This->palettes[PaletteNumber] = HeapAlloc(GetProcessHeap(), 0, sizeof(PALETTEENTRY) * 256);
5671 if (!This->palettes[PaletteNumber]) {
5672 ERR("Out of memory!\n");
5673 return E_OUTOFMEMORY;
5677 for (j = 0; j < 256; ++j) {
5678 This->palettes[PaletteNumber][j].peRed = pEntries[j].peRed;
5679 This->palettes[PaletteNumber][j].peGreen = pEntries[j].peGreen;
5680 This->palettes[PaletteNumber][j].peBlue = pEntries[j].peBlue;
5681 This->palettes[PaletteNumber][j].peFlags = pEntries[j].peFlags;
5683 if (PaletteNumber == This->currentPalette) dirtify_p8_texture_samplers(This);
5684 TRACE("(%p) : returning\n", This);
5685 return WINED3D_OK;
5688 static HRESULT WINAPI IWineD3DDeviceImpl_GetPaletteEntries(IWineD3DDevice *iface, UINT PaletteNumber, PALETTEENTRY* pEntries) {
5689 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5690 int j;
5691 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5692 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5693 /* What happens in such situation isn't documented; Native seems to silently abort
5694 on such conditions. Return Invalid Call. */
5695 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5696 return WINED3DERR_INVALIDCALL;
5698 for (j = 0; j < 256; ++j) {
5699 pEntries[j].peRed = This->palettes[PaletteNumber][j].peRed;
5700 pEntries[j].peGreen = This->palettes[PaletteNumber][j].peGreen;
5701 pEntries[j].peBlue = This->palettes[PaletteNumber][j].peBlue;
5702 pEntries[j].peFlags = This->palettes[PaletteNumber][j].peFlags;
5704 TRACE("(%p) : returning\n", This);
5705 return WINED3D_OK;
5708 static HRESULT WINAPI IWineD3DDeviceImpl_SetCurrentTexturePalette(IWineD3DDevice *iface, UINT PaletteNumber) {
5709 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5710 TRACE("(%p) : PaletteNumber %u\n", This, PaletteNumber);
5711 /* Native appears to silently abort on attempt to make an uninitialized palette current and render.
5712 (tested with reference rasterizer). Return Invalid Call. */
5713 if (PaletteNumber >= This->NumberOfPalettes || !This->palettes[PaletteNumber]) {
5714 ERR("(%p) : (%u) Nonexistent palette. NumberOfPalettes %u\n", This, PaletteNumber, This->NumberOfPalettes);
5715 return WINED3DERR_INVALIDCALL;
5717 /*TODO: stateblocks */
5718 if (This->currentPalette != PaletteNumber) {
5719 This->currentPalette = PaletteNumber;
5720 dirtify_p8_texture_samplers(This);
5722 TRACE("(%p) : returning\n", This);
5723 return WINED3D_OK;
5726 static HRESULT WINAPI IWineD3DDeviceImpl_GetCurrentTexturePalette(IWineD3DDevice *iface, UINT* PaletteNumber) {
5727 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5728 if (PaletteNumber == NULL) {
5729 WARN("(%p) : returning Invalid Call\n", This);
5730 return WINED3DERR_INVALIDCALL;
5732 /*TODO: stateblocks */
5733 *PaletteNumber = This->currentPalette;
5734 TRACE("(%p) : returning %u\n", This, *PaletteNumber);
5735 return WINED3D_OK;
5738 static HRESULT WINAPI IWineD3DDeviceImpl_SetSoftwareVertexProcessing(IWineD3DDevice *iface, BOOL bSoftware) {
5739 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5740 static BOOL showFixmes = TRUE;
5741 if (showFixmes) {
5742 FIXME("(%p) : stub\n", This);
5743 showFixmes = FALSE;
5746 This->softwareVertexProcessing = bSoftware;
5747 return WINED3D_OK;
5751 static BOOL WINAPI IWineD3DDeviceImpl_GetSoftwareVertexProcessing(IWineD3DDevice *iface) {
5752 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5753 static BOOL showFixmes = TRUE;
5754 if (showFixmes) {
5755 FIXME("(%p) : stub\n", This);
5756 showFixmes = FALSE;
5758 return This->softwareVertexProcessing;
5762 static HRESULT WINAPI IWineD3DDeviceImpl_GetRasterStatus(IWineD3DDevice *iface, UINT iSwapChain, WINED3DRASTER_STATUS* pRasterStatus) {
5763 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5764 IWineD3DSwapChain *swapChain;
5765 HRESULT hr;
5767 TRACE("(%p) : SwapChain %d returning %p\n", This, iSwapChain, pRasterStatus);
5769 hr = IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapChain);
5770 if(hr == WINED3D_OK){
5771 hr = IWineD3DSwapChain_GetRasterStatus(swapChain, pRasterStatus);
5772 IWineD3DSwapChain_Release(swapChain);
5773 }else{
5774 FIXME("(%p) IWineD3DSwapChain_GetRasterStatus returned in error\n", This);
5776 return hr;
5780 static HRESULT WINAPI IWineD3DDeviceImpl_SetNPatchMode(IWineD3DDevice *iface, float nSegments) {
5781 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5782 static BOOL showfixmes = TRUE;
5783 if(nSegments != 0.0f) {
5784 if( showfixmes) {
5785 FIXME("(%p) : stub nSegments(%f)\n", This, nSegments);
5786 showfixmes = FALSE;
5789 return WINED3D_OK;
5792 static float WINAPI IWineD3DDeviceImpl_GetNPatchMode(IWineD3DDevice *iface) {
5793 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
5794 static BOOL showfixmes = TRUE;
5795 if( showfixmes) {
5796 FIXME("(%p) : stub returning(%f)\n", This, 0.0f);
5797 showfixmes = FALSE;
5799 return 0.0f;
5802 static HRESULT WINAPI IWineD3DDeviceImpl_UpdateSurface(IWineD3DDevice *iface, IWineD3DSurface *pSourceSurface, CONST RECT* pSourceRect, IWineD3DSurface *pDestinationSurface, CONST POINT* pDestPoint) {
5803 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
5804 /** TODO: remove casts to IWineD3DSurfaceImpl
5805 * NOTE: move code to surface to accomplish this
5806 ****************************************/
5807 IWineD3DSurfaceImpl *pSrcSurface = (IWineD3DSurfaceImpl *)pSourceSurface;
5808 int srcWidth, srcHeight;
5809 unsigned int srcSurfaceWidth, srcSurfaceHeight, destSurfaceWidth, destSurfaceHeight;
5810 WINED3DFORMAT destFormat, srcFormat;
5811 UINT destSize;
5812 int srcLeft, destLeft, destTop;
5813 WINED3DPOOL srcPool, destPool;
5814 int offset = 0;
5815 int rowoffset = 0; /* how many bytes to add onto the end of a row to wraparound to the beginning of the next */
5816 glDescriptor *glDescription = NULL;
5817 GLenum dummy;
5818 int sampler;
5819 int bpp;
5820 CONVERT_TYPES convert = NO_CONVERSION;
5822 WINED3DSURFACE_DESC winedesc;
5824 TRACE("(%p) : Source (%p) Rect (%p) Destination (%p) Point(%p)\n", This, pSourceSurface, pSourceRect, pDestinationSurface, pDestPoint);
5825 memset(&winedesc, 0, sizeof(winedesc));
5826 winedesc.Width = &srcSurfaceWidth;
5827 winedesc.Height = &srcSurfaceHeight;
5828 winedesc.Pool = &srcPool;
5829 winedesc.Format = &srcFormat;
5831 IWineD3DSurface_GetDesc(pSourceSurface, &winedesc);
5833 winedesc.Width = &destSurfaceWidth;
5834 winedesc.Height = &destSurfaceHeight;
5835 winedesc.Pool = &destPool;
5836 winedesc.Format = &destFormat;
5837 winedesc.Size = &destSize;
5839 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5841 if(srcPool != WINED3DPOOL_SYSTEMMEM || destPool != WINED3DPOOL_DEFAULT){
5842 WARN("source %p must be SYSTEMMEM and dest %p must be DEFAULT, returning WINED3DERR_INVALIDCALL\n", pSourceSurface, pDestinationSurface);
5843 return WINED3DERR_INVALIDCALL;
5846 /* This call loads the opengl surface directly, instead of copying the surface to the
5847 * destination's sysmem copy. If surface conversion is needed, use BltFast instead to
5848 * copy in sysmem and use regular surface loading.
5850 d3dfmt_get_conv((IWineD3DSurfaceImpl *) pDestinationSurface, FALSE, TRUE,
5851 &dummy, &dummy, &dummy, &convert, &bpp, FALSE);
5852 if(convert != NO_CONVERSION) {
5853 return IWineD3DSurface_BltFast(pDestinationSurface,
5854 pDestPoint ? pDestPoint->x : 0,
5855 pDestPoint ? pDestPoint->y : 0,
5856 pSourceSurface, (RECT *) pSourceRect, 0);
5859 if (destFormat == WINED3DFMT_UNKNOWN) {
5860 TRACE("(%p) : Converting destination surface from WINED3DFMT_UNKNOWN to the source format\n", This);
5861 IWineD3DSurface_SetFormat(pDestinationSurface, srcFormat);
5863 /* Get the update surface description */
5864 IWineD3DSurface_GetDesc(pDestinationSurface, &winedesc);
5867 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
5869 ENTER_GL();
5871 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
5872 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
5873 checkGLcall("glActiveTextureARB");
5876 /* Make sure the surface is loaded and up to date */
5877 IWineD3DSurface_PreLoad(pDestinationSurface);
5878 IWineD3DSurface_BindTexture(pDestinationSurface);
5880 IWineD3DSurface_GetGlDesc(pDestinationSurface, &glDescription);
5882 /* this needs to be done in lines if the sourceRect != the sourceWidth */
5883 srcWidth = pSourceRect ? pSourceRect->right - pSourceRect->left : srcSurfaceWidth;
5884 srcHeight = pSourceRect ? pSourceRect->bottom - pSourceRect->top : srcSurfaceHeight;
5885 srcLeft = pSourceRect ? pSourceRect->left : 0;
5886 destLeft = pDestPoint ? pDestPoint->x : 0;
5887 destTop = pDestPoint ? pDestPoint->y : 0;
5890 /* This function doesn't support compressed textures
5891 the pitch is just bytesPerPixel * width */
5892 if(srcWidth != srcSurfaceWidth || srcLeft ){
5893 rowoffset = srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5894 offset += srcLeft * pSrcSurface->bytesPerPixel;
5895 /* TODO: do we ever get 3bpp?, would a shift and an add be quicker than a mul (well maybe a cycle or two) */
5897 /* TODO DXT formats */
5899 if(pSourceRect != NULL && pSourceRect->top != 0){
5900 offset += pSourceRect->top * srcSurfaceWidth * pSrcSurface->bytesPerPixel;
5902 TRACE("(%p) glTexSubImage2D, Level %d, left %d, top %d, width %d, height %d , ftm %d, type %d, memory %p\n"
5903 ,This
5904 ,glDescription->level
5905 ,destLeft
5906 ,destTop
5907 ,srcWidth
5908 ,srcHeight
5909 ,glDescription->glFormat
5910 ,glDescription->glType
5911 ,IWineD3DSurface_GetData(pSourceSurface)
5914 /* Sanity check */
5915 if (IWineD3DSurface_GetData(pSourceSurface) == NULL) {
5917 /* need to lock the surface to get the data */
5918 FIXME("Surfaces has no allocated memory, but should be an in memory only surface\n");
5921 /* TODO: Cube and volume support */
5922 if(rowoffset != 0){
5923 /* not a whole row so we have to do it a line at a time */
5924 int j;
5926 /* hopefully using pointer addition will be quicker than using a point + j * rowoffset */
5927 const unsigned char* data =((const unsigned char *)IWineD3DSurface_GetData(pSourceSurface)) + offset;
5929 for(j = destTop ; j < (srcHeight + destTop) ; j++){
5931 glTexSubImage2D(glDescription->target
5932 ,glDescription->level
5933 ,destLeft
5935 ,srcWidth
5937 ,glDescription->glFormat
5938 ,glDescription->glType
5939 ,data /* could be quicker using */
5941 data += rowoffset;
5944 } else { /* Full width, so just write out the whole texture */
5946 if (WINED3DFMT_DXT1 == destFormat ||
5947 WINED3DFMT_DXT2 == destFormat ||
5948 WINED3DFMT_DXT3 == destFormat ||
5949 WINED3DFMT_DXT4 == destFormat ||
5950 WINED3DFMT_DXT5 == destFormat) {
5951 if (GL_SUPPORT(EXT_TEXTURE_COMPRESSION_S3TC)) {
5952 if (destSurfaceHeight != srcHeight || destSurfaceWidth != srcWidth) {
5953 /* FIXME: The easy way to do this is to lock the destination, and copy the bits across */
5954 FIXME("Updating part of a compressed texture is not supported at the moment\n");
5955 } if (destFormat != srcFormat) {
5956 FIXME("Updating mixed format compressed texture is not curretly support\n");
5957 } else {
5958 GL_EXTCALL(glCompressedTexImage2DARB)(glDescription->target,
5959 glDescription->level,
5960 glDescription->glFormatInternal,
5961 srcWidth,
5962 srcHeight,
5964 destSize,
5965 IWineD3DSurface_GetData(pSourceSurface));
5967 } else {
5968 FIXME("Attempting to update a DXT compressed texture without hardware support\n");
5972 } else {
5973 glTexSubImage2D(glDescription->target
5974 ,glDescription->level
5975 ,destLeft
5976 ,destTop
5977 ,srcWidth
5978 ,srcHeight
5979 ,glDescription->glFormat
5980 ,glDescription->glType
5981 ,IWineD3DSurface_GetData(pSourceSurface)
5985 checkGLcall("glTexSubImage2D");
5987 LEAVE_GL();
5989 IWineD3DSurface_ModifyLocation(pDestinationSurface, SFLAG_INTEXTURE, TRUE);
5990 sampler = This->rev_tex_unit_map[0];
5991 if (sampler != -1) {
5992 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
5995 return WINED3D_OK;
5998 static HRESULT WINAPI IWineD3DDeviceImpl_DrawRectPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DRECTPATCH_INFO* pRectPatchInfo) {
5999 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6000 struct WineD3DRectPatch *patch;
6001 unsigned int i;
6002 struct list *e;
6003 BOOL found;
6004 TRACE("(%p) Handle(%d) noSegs(%p) rectpatch(%p)\n", This, Handle, pNumSegs, pRectPatchInfo);
6006 if(!(Handle || pRectPatchInfo)) {
6007 /* TODO: Write a test for the return value, thus the FIXME */
6008 FIXME("Both Handle and pRectPatchInfo are NULL\n");
6009 return WINED3DERR_INVALIDCALL;
6012 if(Handle) {
6013 i = PATCHMAP_HASHFUNC(Handle);
6014 found = FALSE;
6015 LIST_FOR_EACH(e, &This->patches[i]) {
6016 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6017 if(patch->Handle == Handle) {
6018 found = TRUE;
6019 break;
6023 if(!found) {
6024 TRACE("Patch does not exist. Creating a new one\n");
6025 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6026 patch->Handle = Handle;
6027 list_add_head(&This->patches[i], &patch->entry);
6028 } else {
6029 TRACE("Found existing patch %p\n", patch);
6031 } else {
6032 /* Since opengl does not load tesselated vertex attributes into numbered vertex
6033 * attributes we have to tesselate, read back, and draw. This needs a patch
6034 * management structure instance. Create one.
6036 * A possible improvement is to check if a vertex shader is used, and if not directly
6037 * draw the patch.
6039 FIXME("Drawing an uncached patch. This is slow\n");
6040 patch = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*patch));
6043 if(pNumSegs[0] != patch->numSegs[0] || pNumSegs[1] != patch->numSegs[1] ||
6044 pNumSegs[2] != patch->numSegs[2] || pNumSegs[3] != patch->numSegs[3] ||
6045 (pRectPatchInfo && memcmp(pRectPatchInfo, &patch->RectPatchInfo, sizeof(*pRectPatchInfo)) != 0) ) {
6046 HRESULT hr;
6047 TRACE("Tesselation density or patch info changed, retesselating\n");
6049 if(pRectPatchInfo) {
6050 patch->RectPatchInfo = *pRectPatchInfo;
6052 patch->numSegs[0] = pNumSegs[0];
6053 patch->numSegs[1] = pNumSegs[1];
6054 patch->numSegs[2] = pNumSegs[2];
6055 patch->numSegs[3] = pNumSegs[3];
6057 hr = tesselate_rectpatch(This, patch);
6058 if(FAILED(hr)) {
6059 WARN("Patch tesselation failed\n");
6061 /* Do not release the handle to store the params of the patch */
6062 if(!Handle) {
6063 HeapFree(GetProcessHeap(), 0, patch);
6065 return hr;
6069 This->currentPatch = patch;
6070 IWineD3DDevice_DrawPrimitiveStrided(iface, WINED3DPT_TRIANGLELIST, patch->numSegs[0] * patch->numSegs[1] * 2, &patch->strided);
6071 This->currentPatch = NULL;
6073 /* Destroy uncached patches */
6074 if(!Handle) {
6075 HeapFree(GetProcessHeap(), 0, patch->mem);
6076 HeapFree(GetProcessHeap(), 0, patch);
6078 return WINED3D_OK;
6081 static HRESULT WINAPI IWineD3DDeviceImpl_DrawTriPatch(IWineD3DDevice *iface, UINT Handle, CONST float* pNumSegs, CONST WINED3DTRIPATCH_INFO* pTriPatchInfo) {
6082 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6083 TRACE("(%p) Handle(%d) noSegs(%p) tripatch(%p)\n", This, Handle, pNumSegs, pTriPatchInfo);
6084 FIXME("(%p) : Stub\n", This);
6085 return WINED3D_OK;
6088 static HRESULT WINAPI IWineD3DDeviceImpl_DeletePatch(IWineD3DDevice *iface, UINT Handle) {
6089 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6090 int i;
6091 struct WineD3DRectPatch *patch;
6092 struct list *e;
6093 TRACE("(%p) Handle(%d)\n", This, Handle);
6095 i = PATCHMAP_HASHFUNC(Handle);
6096 LIST_FOR_EACH(e, &This->patches[i]) {
6097 patch = LIST_ENTRY(e, struct WineD3DRectPatch, entry);
6098 if(patch->Handle == Handle) {
6099 TRACE("Deleting patch %p\n", patch);
6100 list_remove(&patch->entry);
6101 HeapFree(GetProcessHeap(), 0, patch->mem);
6102 HeapFree(GetProcessHeap(), 0, patch);
6103 return WINED3D_OK;
6107 /* TODO: Write a test for the return value */
6108 FIXME("Attempt to destroy nonexistent patch\n");
6109 return WINED3DERR_INVALIDCALL;
6112 static IWineD3DSwapChain *get_swapchain(IWineD3DSurface *target) {
6113 HRESULT hr;
6114 IWineD3DSwapChain *swapchain;
6116 hr = IWineD3DSurface_GetContainer(target, &IID_IWineD3DSwapChain, (void **)&swapchain);
6117 if (SUCCEEDED(hr)) {
6118 IWineD3DSwapChain_Release((IUnknown *)swapchain);
6119 return swapchain;
6122 return NULL;
6125 void bind_fbo(IWineD3DDevice *iface, GLenum target, GLuint *fbo) {
6126 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6128 if (!*fbo) {
6129 GL_EXTCALL(glGenFramebuffersEXT(1, fbo));
6130 checkGLcall("glGenFramebuffersEXT()");
6131 TRACE("Created FBO %d\n", *fbo);
6133 GL_EXTCALL(glBindFramebufferEXT(target, *fbo));
6134 checkGLcall("glBindFramebuffer()");
6137 /* TODO: Handle stencil attachments */
6138 void attach_depth_stencil_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, IWineD3DSurface *depth_stencil, BOOL use_render_buffer) {
6139 IWineD3DSurfaceImpl *depth_stencil_impl = (IWineD3DSurfaceImpl *)depth_stencil;
6141 if (use_render_buffer && depth_stencil_impl->current_renderbuffer) {
6142 GL_EXTCALL(glFramebufferRenderbufferEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, depth_stencil_impl->current_renderbuffer->id));
6143 checkGLcall("glFramebufferRenderbufferEXT()");
6144 } else {
6145 IWineD3DBaseTextureImpl *texture_impl;
6146 GLenum texttarget, target;
6147 GLint old_binding = 0;
6149 texttarget = depth_stencil_impl->glDescription.target;
6150 if(texttarget == GL_TEXTURE_2D) {
6151 target = GL_TEXTURE_2D;
6152 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6153 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6154 target = GL_TEXTURE_RECTANGLE_ARB;
6155 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6156 } else {
6157 target = GL_TEXTURE_CUBE_MAP_ARB;
6158 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6161 IWineD3DSurface_PreLoad(depth_stencil);
6163 glBindTexture(target, depth_stencil_impl->glDescription.textureName);
6164 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6165 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6166 glTexParameteri(target, GL_DEPTH_TEXTURE_MODE_ARB, GL_LUMINANCE);
6167 glBindTexture(target, old_binding);
6169 /* Update base texture states array */
6170 if (SUCCEEDED(IWineD3DSurface_GetContainer(depth_stencil, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6171 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6172 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6173 if (texture_impl->baseTexture.bindCount) {
6174 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6177 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6180 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_DEPTH_ATTACHMENT_EXT, texttarget,
6181 depth_stencil_impl->glDescription.textureName, depth_stencil_impl->glDescription.level));
6182 checkGLcall("glFramebufferTexture2DEXT()");
6186 void attach_surface_fbo(IWineD3DDeviceImpl *This, GLenum fbo_target, DWORD idx, IWineD3DSurface *surface) {
6187 const IWineD3DSurfaceImpl *surface_impl = (IWineD3DSurfaceImpl *)surface;
6188 IWineD3DBaseTextureImpl *texture_impl;
6189 GLenum texttarget, target;
6190 GLint old_binding;
6192 texttarget = surface_impl->glDescription.target;
6193 if(texttarget == GL_TEXTURE_2D) {
6194 target = GL_TEXTURE_2D;
6195 glGetIntegerv(GL_TEXTURE_BINDING_2D, &old_binding);
6196 } else if(texttarget == GL_TEXTURE_RECTANGLE_ARB) {
6197 target = GL_TEXTURE_RECTANGLE_ARB;
6198 glGetIntegerv(GL_TEXTURE_BINDING_RECTANGLE_ARB, &old_binding);
6199 } else {
6200 target = GL_TEXTURE_CUBE_MAP_ARB;
6201 glGetIntegerv(GL_TEXTURE_BINDING_CUBE_MAP_ARB, &old_binding);
6204 IWineD3DSurface_PreLoad(surface);
6206 glBindTexture(target, surface_impl->glDescription.textureName);
6207 glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
6208 glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
6209 glBindTexture(target, old_binding);
6211 /* Update base texture states array */
6212 if (SUCCEEDED(IWineD3DSurface_GetContainer(surface, &IID_IWineD3DBaseTexture, (void **)&texture_impl))) {
6213 texture_impl->baseTexture.states[WINED3DTEXSTA_MINFILTER] = WINED3DTEXF_POINT;
6214 texture_impl->baseTexture.states[WINED3DTEXSTA_MAGFILTER] = WINED3DTEXF_POINT;
6215 if (texture_impl->baseTexture.bindCount) {
6216 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(texture_impl->baseTexture.sampler));
6219 IWineD3DBaseTexture_Release((IWineD3DBaseTexture *)texture_impl);
6222 GL_EXTCALL(glFramebufferTexture2DEXT(fbo_target, GL_COLOR_ATTACHMENT0_EXT + idx, texttarget,
6223 surface_impl->glDescription.textureName, surface_impl->glDescription.level));
6225 checkGLcall("attach_surface_fbo");
6228 static void color_fill_fbo(IWineD3DDevice *iface, IWineD3DSurface *surface, CONST WINED3DRECT *rect, WINED3DCOLOR color) {
6229 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6230 IWineD3DSwapChain *swapchain;
6232 swapchain = get_swapchain(surface);
6233 if (swapchain) {
6234 GLenum buffer;
6236 TRACE("Surface %p is onscreen\n", surface);
6238 ActivateContext(This, surface, CTXUSAGE_RESOURCELOAD);
6239 ENTER_GL();
6240 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6241 buffer = surface_get_gl_buffer(surface, swapchain);
6242 glDrawBuffer(buffer);
6243 checkGLcall("glDrawBuffer()");
6244 } else {
6245 TRACE("Surface %p is offscreen\n", surface);
6247 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6248 ENTER_GL();
6249 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6250 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, 0, surface);
6251 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6252 checkGLcall("glFramebufferRenderbufferEXT");
6255 if (rect) {
6256 glEnable(GL_SCISSOR_TEST);
6257 if(!swapchain) {
6258 glScissor(rect->x1, rect->y1, rect->x2 - rect->x1, rect->y2 - rect->y1);
6259 } else {
6260 glScissor(rect->x1, ((IWineD3DSurfaceImpl *)surface)->currentDesc.Height - rect->y2,
6261 rect->x2 - rect->x1, rect->y2 - rect->y1);
6263 checkGLcall("glScissor");
6264 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SCISSORRECT);
6265 } else {
6266 glDisable(GL_SCISSOR_TEST);
6268 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6270 glDisable(GL_BLEND);
6271 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ALPHABLENDENABLE));
6273 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
6274 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_COLORWRITEENABLE));
6276 glClearColor(D3DCOLOR_R(color), D3DCOLOR_G(color), D3DCOLOR_B(color), D3DCOLOR_A(color));
6277 glClear(GL_COLOR_BUFFER_BIT);
6278 checkGLcall("glClear");
6280 if (This->render_offscreen) {
6281 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6282 } else {
6283 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6284 checkGLcall("glBindFramebuffer()");
6287 if (swapchain && surface == ((IWineD3DSwapChainImpl *)swapchain)->frontBuffer
6288 && ((IWineD3DSwapChainImpl *)swapchain)->backBuffer) {
6289 glDrawBuffer(GL_BACK);
6290 checkGLcall("glDrawBuffer()");
6293 LEAVE_GL();
6296 static inline DWORD argb_to_fmt(DWORD color, WINED3DFORMAT destfmt) {
6297 unsigned int r, g, b, a;
6298 DWORD ret;
6300 if(destfmt == WINED3DFMT_A8R8G8B8 || destfmt == WINED3DFMT_X8R8G8B8 ||
6301 destfmt == WINED3DFMT_R8G8B8)
6302 return color;
6304 TRACE("Converting color %08x to format %s\n", color, debug_d3dformat(destfmt));
6306 a = (color & 0xff000000) >> 24;
6307 r = (color & 0x00ff0000) >> 16;
6308 g = (color & 0x0000ff00) >> 8;
6309 b = (color & 0x000000ff) >> 0;
6311 switch(destfmt)
6313 case WINED3DFMT_R5G6B5:
6314 if(r == 0xff && g == 0xff && b == 0xff) return 0xffff;
6315 r = (r * 32) / 256;
6316 g = (g * 64) / 256;
6317 b = (b * 32) / 256;
6318 ret = r << 11;
6319 ret |= g << 5;
6320 ret |= b;
6321 TRACE("Returning %08x\n", ret);
6322 return ret;
6324 case WINED3DFMT_X1R5G5B5:
6325 case WINED3DFMT_A1R5G5B5:
6326 a = (a * 2) / 256;
6327 r = (r * 32) / 256;
6328 g = (g * 32) / 256;
6329 b = (b * 32) / 256;
6330 ret = a << 15;
6331 ret |= r << 10;
6332 ret |= g << 5;
6333 ret |= b << 0;
6334 TRACE("Returning %08x\n", ret);
6335 return ret;
6337 case WINED3DFMT_A8:
6338 TRACE("Returning %08x\n", a);
6339 return a;
6341 case WINED3DFMT_X4R4G4B4:
6342 case WINED3DFMT_A4R4G4B4:
6343 a = (a * 16) / 256;
6344 r = (r * 16) / 256;
6345 g = (g * 16) / 256;
6346 b = (b * 16) / 256;
6347 ret = a << 12;
6348 ret |= r << 8;
6349 ret |= g << 4;
6350 ret |= b << 0;
6351 TRACE("Returning %08x\n", ret);
6352 return ret;
6354 case WINED3DFMT_R3G3B2:
6355 r = (r * 8) / 256;
6356 g = (g * 8) / 256;
6357 b = (b * 4) / 256;
6358 ret = r << 5;
6359 ret |= g << 2;
6360 ret |= b << 0;
6361 TRACE("Returning %08x\n", ret);
6362 return ret;
6364 case WINED3DFMT_X8B8G8R8:
6365 case WINED3DFMT_A8B8G8R8:
6366 ret = a << 24;
6367 ret |= b << 16;
6368 ret |= g << 8;
6369 ret |= r << 0;
6370 TRACE("Returning %08x\n", ret);
6371 return ret;
6373 case WINED3DFMT_A2R10G10B10:
6374 a = (a * 4) / 256;
6375 r = (r * 1024) / 256;
6376 g = (g * 1024) / 256;
6377 b = (b * 1024) / 256;
6378 ret = a << 30;
6379 ret |= r << 20;
6380 ret |= g << 10;
6381 ret |= b << 0;
6382 TRACE("Returning %08x\n", ret);
6383 return ret;
6385 case WINED3DFMT_A2B10G10R10:
6386 a = (a * 4) / 256;
6387 r = (r * 1024) / 256;
6388 g = (g * 1024) / 256;
6389 b = (b * 1024) / 256;
6390 ret = a << 30;
6391 ret |= b << 20;
6392 ret |= g << 10;
6393 ret |= r << 0;
6394 TRACE("Returning %08x\n", ret);
6395 return ret;
6397 default:
6398 FIXME("Add a COLORFILL conversion for format %s\n", debug_d3dformat(destfmt));
6399 return 0;
6403 static HRESULT WINAPI IWineD3DDeviceImpl_ColorFill(IWineD3DDevice *iface, IWineD3DSurface *pSurface, CONST WINED3DRECT* pRect, WINED3DCOLOR color) {
6404 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6405 IWineD3DSurfaceImpl *surface = (IWineD3DSurfaceImpl *) pSurface;
6406 WINEDDBLTFX BltFx;
6407 TRACE("(%p) Colour fill Surface: %p rect: %p color: 0x%08x\n", This, pSurface, pRect, color);
6409 if (surface->resource.pool != WINED3DPOOL_DEFAULT && surface->resource.pool != WINED3DPOOL_SYSTEMMEM) {
6410 FIXME("call to colorfill with non WINED3DPOOL_DEFAULT or WINED3DPOOL_SYSTEMMEM surface\n");
6411 return WINED3DERR_INVALIDCALL;
6414 if (wined3d_settings.offscreen_rendering_mode == ORM_FBO) {
6415 color_fill_fbo(iface, pSurface, pRect, color);
6416 return WINED3D_OK;
6417 } else {
6418 /* Just forward this to the DirectDraw blitting engine */
6419 memset(&BltFx, 0, sizeof(BltFx));
6420 BltFx.dwSize = sizeof(BltFx);
6421 BltFx.u5.dwFillColor = argb_to_fmt(color, surface->resource.format);
6422 return IWineD3DSurface_Blt(pSurface, (RECT *) pRect, NULL, NULL, WINEDDBLT_COLORFILL, &BltFx, WINED3DTEXF_NONE);
6426 /* rendertarget and depth stencil functions */
6427 static HRESULT WINAPI IWineD3DDeviceImpl_GetRenderTarget(IWineD3DDevice* iface,DWORD RenderTargetIndex, IWineD3DSurface **ppRenderTarget) {
6428 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6430 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6431 ERR("(%p) : Only %d render targets are supported.\n", This, GL_LIMITS(buffers));
6432 return WINED3DERR_INVALIDCALL;
6435 *ppRenderTarget = This->render_targets[RenderTargetIndex];
6436 TRACE("(%p) : RenderTarget %d Index returning %p\n", This, RenderTargetIndex, *ppRenderTarget);
6437 /* Note inc ref on returned surface */
6438 if(*ppRenderTarget != NULL)
6439 IWineD3DSurface_AddRef(*ppRenderTarget);
6440 return WINED3D_OK;
6443 static HRESULT WINAPI IWineD3DDeviceImpl_SetFrontBackBuffers(IWineD3DDevice *iface, IWineD3DSurface *Front, IWineD3DSurface *Back) {
6444 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6445 IWineD3DSurfaceImpl *FrontImpl = (IWineD3DSurfaceImpl *) Front;
6446 IWineD3DSurfaceImpl *BackImpl = (IWineD3DSurfaceImpl *) Back;
6447 IWineD3DSwapChainImpl *Swapchain;
6448 HRESULT hr;
6450 TRACE("(%p)->(%p,%p)\n", This, FrontImpl, BackImpl);
6452 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &Swapchain);
6453 if(hr != WINED3D_OK) {
6454 ERR("Can't get the swapchain\n");
6455 return hr;
6458 /* Make sure to release the swapchain */
6459 IWineD3DSwapChain_Release((IWineD3DSwapChain *) Swapchain);
6461 if(FrontImpl && !(FrontImpl->resource.usage & WINED3DUSAGE_RENDERTARGET) ) {
6462 ERR("Trying to set a front buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6463 return WINED3DERR_INVALIDCALL;
6465 else if(BackImpl && !(BackImpl->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6466 ERR("Trying to set a back buffer which doesn't have WINED3DUSAGE_RENDERTARGET usage\n");
6467 return WINED3DERR_INVALIDCALL;
6470 if(Swapchain->frontBuffer != Front) {
6471 TRACE("Changing the front buffer from %p to %p\n", Swapchain->frontBuffer, Front);
6473 if(Swapchain->frontBuffer)
6474 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, NULL);
6475 Swapchain->frontBuffer = Front;
6477 if(Swapchain->frontBuffer) {
6478 IWineD3DSurface_SetContainer(Swapchain->frontBuffer, (IWineD3DBase *) Swapchain);
6482 if(Back && !Swapchain->backBuffer) {
6483 /* We need memory for the back buffer array - only one back buffer this way */
6484 Swapchain->backBuffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IWineD3DSurface *));
6485 if(!Swapchain->backBuffer) {
6486 ERR("Out of memory\n");
6487 return E_OUTOFMEMORY;
6491 if(Swapchain->backBuffer[0] != Back) {
6492 TRACE("Changing the back buffer from %p to %p\n", Swapchain->backBuffer, Back);
6494 /* What to do about the context here in the case of multithreading? Not sure.
6495 * This function is called by IDirect3D7::CreateDevice so in theory its initialization code
6497 ENTER_GL();
6498 if(!Swapchain->backBuffer[0]) {
6499 /* GL was told to draw to the front buffer at creation,
6500 * undo that
6502 glDrawBuffer(GL_BACK);
6503 checkGLcall("glDrawBuffer(GL_BACK)");
6504 /* Set the backbuffer count to 1 because other code uses it to fing the back buffers */
6505 Swapchain->presentParms.BackBufferCount = 1;
6506 } else if (!Back) {
6507 /* That makes problems - disable for now */
6508 /* glDrawBuffer(GL_FRONT); */
6509 checkGLcall("glDrawBuffer(GL_FRONT)");
6510 /* We have lost our back buffer, set this to 0 to avoid confusing other code */
6511 Swapchain->presentParms.BackBufferCount = 0;
6513 LEAVE_GL();
6515 if(Swapchain->backBuffer[0])
6516 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], NULL);
6517 Swapchain->backBuffer[0] = Back;
6519 if(Swapchain->backBuffer[0]) {
6520 IWineD3DSurface_SetContainer(Swapchain->backBuffer[0], (IWineD3DBase *) Swapchain);
6521 } else {
6522 HeapFree(GetProcessHeap(), 0, Swapchain->backBuffer);
6523 Swapchain->backBuffer = NULL;
6528 return WINED3D_OK;
6531 static HRESULT WINAPI IWineD3DDeviceImpl_GetDepthStencilSurface(IWineD3DDevice* iface, IWineD3DSurface **ppZStencilSurface) {
6532 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6533 *ppZStencilSurface = This->stencilBufferTarget;
6534 TRACE("(%p) : zStencilSurface returning %p\n", This, *ppZStencilSurface);
6536 if(*ppZStencilSurface != NULL) {
6537 /* Note inc ref on returned surface */
6538 IWineD3DSurface_AddRef(*ppZStencilSurface);
6539 return WINED3D_OK;
6540 } else {
6541 return WINED3DERR_NOTFOUND;
6545 /* TODO: Handle stencil attachments */
6546 static void set_depth_stencil_fbo(IWineD3DDevice *iface, IWineD3DSurface *depth_stencil) {
6547 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6549 TRACE("Set depth stencil to %p\n", depth_stencil);
6551 if (depth_stencil) {
6552 attach_depth_stencil_fbo(This, GL_FRAMEBUFFER_EXT, depth_stencil, TRUE);
6553 } else {
6554 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_TEXTURE_2D, 0, 0));
6555 checkGLcall("glFramebufferTexture2DEXT()");
6559 static void set_render_target_fbo(IWineD3DDevice *iface, DWORD idx, IWineD3DSurface *render_target) {
6560 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6562 TRACE("Set render target %u to %p\n", idx, render_target);
6564 if (render_target) {
6565 attach_surface_fbo(This, GL_FRAMEBUFFER_EXT, idx, render_target);
6566 This->draw_buffers[idx] = GL_COLOR_ATTACHMENT0_EXT + idx;
6567 } else {
6568 GL_EXTCALL(glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + idx, GL_TEXTURE_2D, 0, 0));
6569 checkGLcall("glFramebufferTexture2DEXT()");
6571 This->draw_buffers[idx] = GL_NONE;
6575 static void check_fbo_status(IWineD3DDevice *iface) {
6576 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6577 GLenum status;
6579 status = GL_EXTCALL(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
6580 if (status == GL_FRAMEBUFFER_COMPLETE_EXT) {
6581 TRACE("FBO complete\n");
6582 } else {
6583 IWineD3DSurfaceImpl *attachment;
6584 int i;
6585 FIXME("FBO status %s (%#x)\n", debug_fbostatus(status), status);
6587 /* Dump the FBO attachments */
6588 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6589 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_color_attachments[i];
6590 if (attachment) {
6591 FIXME("\tColor attachment %d: (%p) %s %ux%u\n", i, attachment, debug_d3dformat(attachment->resource.format),
6592 attachment->pow2Width, attachment->pow2Height);
6595 attachment = (IWineD3DSurfaceImpl *)This->activeContext->fbo_depth_attachment;
6596 if (attachment) {
6597 FIXME("\tDepth attachment: (%p) %s %ux%u\n", attachment, debug_d3dformat(attachment->resource.format),
6598 attachment->pow2Width, attachment->pow2Height);
6603 static BOOL depth_mismatch_fbo(IWineD3DDevice *iface) {
6604 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6605 IWineD3DSurfaceImpl *rt_impl = (IWineD3DSurfaceImpl *)This->render_targets[0];
6606 IWineD3DSurfaceImpl *ds_impl = (IWineD3DSurfaceImpl *)This->stencilBufferTarget;
6608 if (!ds_impl) return FALSE;
6610 if (ds_impl->current_renderbuffer) {
6611 return (rt_impl->pow2Width != ds_impl->current_renderbuffer->width ||
6612 rt_impl->pow2Height != ds_impl->current_renderbuffer->height);
6615 return (rt_impl->pow2Width != ds_impl->pow2Width ||
6616 rt_impl->pow2Height != ds_impl->pow2Height);
6619 void apply_fbo_state(IWineD3DDevice *iface) {
6620 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6621 WineD3DContext *context = This->activeContext;
6622 unsigned int i;
6624 if (This->render_offscreen) {
6625 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &context->fbo);
6627 /* Apply render targets */
6628 for (i = 0; i < GL_LIMITS(buffers); ++i) {
6629 IWineD3DSurface *render_target = This->render_targets[i];
6630 if (context->fbo_color_attachments[i] != render_target) {
6631 set_render_target_fbo(iface, i, render_target);
6632 context->fbo_color_attachments[i] = render_target;
6636 /* Apply depth targets */
6637 if (context->fbo_depth_attachment != This->stencilBufferTarget || depth_mismatch_fbo(iface)) {
6638 unsigned int w = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Width;
6639 unsigned int h = ((IWineD3DSurfaceImpl *)This->render_targets[0])->pow2Height;
6641 if (This->stencilBufferTarget) {
6642 surface_set_compatible_renderbuffer(This->stencilBufferTarget, w, h);
6644 set_depth_stencil_fbo(iface, This->stencilBufferTarget);
6645 context->fbo_depth_attachment = This->stencilBufferTarget;
6647 } else {
6648 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6651 check_fbo_status(iface);
6654 void stretch_rect_fbo(IWineD3DDevice *iface, IWineD3DSurface *src_surface, WINED3DRECT *src_rect,
6655 IWineD3DSurface *dst_surface, WINED3DRECT *dst_rect, const WINED3DTEXTUREFILTERTYPE filter, BOOL flip) {
6656 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6657 GLbitfield mask = GL_COLOR_BUFFER_BIT; /* TODO: Support blitting depth/stencil surfaces */
6658 IWineD3DSwapChain *src_swapchain, *dst_swapchain;
6659 GLenum gl_filter;
6660 POINT offset = {0, 0};
6662 TRACE("(%p) : src_surface %p, src_rect %p, dst_surface %p, dst_rect %p, filter %s (0x%08x), flip %u\n",
6663 This, src_surface, src_rect, dst_surface, dst_rect, debug_d3dtexturefiltertype(filter), filter, flip);
6664 TRACE("src_rect [%u, %u]->[%u, %u]\n", src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2);
6665 TRACE("dst_rect [%u, %u]->[%u, %u]\n", dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2);
6667 switch (filter) {
6668 case WINED3DTEXF_LINEAR:
6669 gl_filter = GL_LINEAR;
6670 break;
6672 default:
6673 FIXME("Unsupported filter mode %s (0x%08x)\n", debug_d3dtexturefiltertype(filter), filter);
6674 case WINED3DTEXF_NONE:
6675 case WINED3DTEXF_POINT:
6676 gl_filter = GL_NEAREST;
6677 break;
6680 /* Attach src surface to src fbo */
6681 src_swapchain = get_swapchain(src_surface);
6682 if (src_swapchain) {
6683 GLenum buffer = surface_get_gl_buffer(src_surface, src_swapchain);
6685 TRACE("Source surface %p is onscreen\n", src_surface);
6686 ActivateContext(This, src_surface, CTXUSAGE_RESOURCELOAD);
6687 /* Make sure the drawable is up to date. In the offscreen case
6688 * attach_surface_fbo() implicitly takes care of this. */
6689 IWineD3DSurface_LoadLocation(src_surface, SFLAG_INDRAWABLE, NULL);
6691 if(buffer == GL_FRONT) {
6692 RECT windowsize;
6693 UINT h;
6694 ClientToScreen(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &offset);
6695 GetClientRect(((IWineD3DSwapChainImpl *)src_swapchain)->win_handle, &windowsize);
6696 h = windowsize.bottom - windowsize.top;
6697 src_rect->x1 -= offset.x; src_rect->x2 -=offset.x;
6698 src_rect->y1 = offset.y + h - src_rect->y1;
6699 src_rect->y2 = offset.y + h - src_rect->y2;
6700 } else {
6701 src_rect->y1 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y1;
6702 src_rect->y2 = ((IWineD3DSurfaceImpl *)src_surface)->currentDesc.Height - src_rect->y2;
6705 ENTER_GL();
6706 GL_EXTCALL(glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0));
6707 glReadBuffer(buffer);
6708 checkGLcall("glReadBuffer()");
6709 } else {
6710 TRACE("Source surface %p is offscreen\n", src_surface);
6711 ENTER_GL();
6712 bind_fbo(iface, GL_READ_FRAMEBUFFER_EXT, &This->activeContext->src_fbo);
6713 attach_surface_fbo(This, GL_READ_FRAMEBUFFER_EXT, 0, src_surface);
6714 glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
6715 checkGLcall("glReadBuffer()");
6716 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_READ_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6717 checkGLcall("glFramebufferRenderbufferEXT");
6719 LEAVE_GL();
6721 /* Attach dst surface to dst fbo */
6722 dst_swapchain = get_swapchain(dst_surface);
6723 if (dst_swapchain) {
6724 GLenum buffer = surface_get_gl_buffer(dst_surface, dst_swapchain);
6726 TRACE("Destination surface %p is onscreen\n", dst_surface);
6727 ActivateContext(This, dst_surface, CTXUSAGE_RESOURCELOAD);
6728 /* Make sure the drawable is up to date. In the offscreen case
6729 * attach_surface_fbo() implicitly takes care of this. */
6730 IWineD3DSurface_LoadLocation(dst_surface, SFLAG_INDRAWABLE, NULL);
6732 if(buffer == GL_FRONT) {
6733 RECT windowsize;
6734 UINT h;
6735 ClientToScreen(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &offset);
6736 GetClientRect(((IWineD3DSwapChainImpl *)dst_swapchain)->win_handle, &windowsize);
6737 h = windowsize.bottom - windowsize.top;
6738 dst_rect->x1 -= offset.x; dst_rect->x2 -=offset.x;
6739 dst_rect->y1 = offset.y + h - dst_rect->y1;
6740 dst_rect->y2 = offset.y + h - dst_rect->y2;
6741 } else {
6742 /* Screen coords = window coords, surface height = window height */
6743 dst_rect->y1 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y1;
6744 dst_rect->y2 = ((IWineD3DSurfaceImpl *)dst_surface)->currentDesc.Height - dst_rect->y2;
6747 ENTER_GL();
6748 GL_EXTCALL(glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0));
6749 glDrawBuffer(buffer);
6750 checkGLcall("glDrawBuffer()");
6751 } else {
6752 TRACE("Destination surface %p is offscreen\n", dst_surface);
6754 /* No src or dst swapchain? Make sure some context is active(multithreading) */
6755 if(!src_swapchain) {
6756 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6759 ENTER_GL();
6760 bind_fbo(iface, GL_DRAW_FRAMEBUFFER_EXT, &This->activeContext->dst_fbo);
6761 attach_surface_fbo(This, GL_DRAW_FRAMEBUFFER_EXT, 0, dst_surface);
6762 glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
6763 checkGLcall("glDrawBuffer()");
6764 GL_EXTCALL(glFramebufferRenderbufferEXT(GL_DRAW_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, 0));
6765 checkGLcall("glFramebufferRenderbufferEXT");
6767 glDisable(GL_SCISSOR_TEST);
6768 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_SCISSORTESTENABLE));
6770 if (flip) {
6771 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6772 dst_rect->x1, dst_rect->y2, dst_rect->x2, dst_rect->y1, mask, gl_filter));
6773 checkGLcall("glBlitFramebuffer()");
6774 } else {
6775 GL_EXTCALL(glBlitFramebufferEXT(src_rect->x1, src_rect->y1, src_rect->x2, src_rect->y2,
6776 dst_rect->x1, dst_rect->y1, dst_rect->x2, dst_rect->y2, mask, gl_filter));
6777 checkGLcall("glBlitFramebuffer()");
6780 IWineD3DSurface_ModifyLocation(dst_surface, SFLAG_INDRAWABLE, TRUE);
6782 if (This->render_offscreen) {
6783 bind_fbo(iface, GL_FRAMEBUFFER_EXT, &This->activeContext->fbo);
6784 } else {
6785 GL_EXTCALL(glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0));
6786 checkGLcall("glBindFramebuffer()");
6789 /* If we switched from GL_BACK to GL_FRONT above, we need to switch back here */
6790 if (dst_swapchain && dst_surface == ((IWineD3DSwapChainImpl *)dst_swapchain)->frontBuffer
6791 && ((IWineD3DSwapChainImpl *)dst_swapchain)->backBuffer) {
6792 glDrawBuffer(GL_BACK);
6793 checkGLcall("glDrawBuffer()");
6795 LEAVE_GL();
6798 static HRESULT WINAPI IWineD3DDeviceImpl_SetRenderTarget(IWineD3DDevice *iface, DWORD RenderTargetIndex, IWineD3DSurface *pRenderTarget) {
6799 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6800 WINED3DVIEWPORT viewport;
6802 TRACE("(%p) : Setting rendertarget %d to %p\n", This, RenderTargetIndex, pRenderTarget);
6804 if (RenderTargetIndex >= GL_LIMITS(buffers)) {
6805 WARN("(%p) : Unsupported target %u set, returning WINED3DERR_INVALIDCALL(only %u supported)\n",
6806 This, RenderTargetIndex, GL_LIMITS(buffers));
6807 return WINED3DERR_INVALIDCALL;
6810 /* MSDN says that null disables the render target
6811 but a device must always be associated with a render target
6812 nope MSDN says that we return invalid call to a null rendertarget with an index of 0
6814 if (RenderTargetIndex == 0 && pRenderTarget == NULL) {
6815 FIXME("Trying to set render target 0 to NULL\n");
6816 return WINED3DERR_INVALIDCALL;
6818 if (pRenderTarget && !(((IWineD3DSurfaceImpl *)pRenderTarget)->resource.usage & WINED3DUSAGE_RENDERTARGET)) {
6819 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);
6820 return WINED3DERR_INVALIDCALL;
6823 /* If we are trying to set what we already have, don't bother */
6824 if (pRenderTarget == This->render_targets[RenderTargetIndex]) {
6825 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6826 return WINED3D_OK;
6828 if(pRenderTarget) IWineD3DSurface_AddRef(pRenderTarget);
6829 if(This->render_targets[RenderTargetIndex]) IWineD3DSurface_Release(This->render_targets[RenderTargetIndex]);
6830 This->render_targets[RenderTargetIndex] = pRenderTarget;
6832 /* Render target 0 is special */
6833 if(RenderTargetIndex == 0) {
6834 /* Finally, reset the viewport as the MSDN states. */
6835 viewport.Height = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Height;
6836 viewport.Width = ((IWineD3DSurfaceImpl *)This->render_targets[0])->currentDesc.Width;
6837 viewport.X = 0;
6838 viewport.Y = 0;
6839 viewport.MaxZ = 1.0f;
6840 viewport.MinZ = 0.0f;
6841 IWineD3DDeviceImpl_SetViewport(iface, &viewport);
6842 /* Make sure the viewport state is dirty, because the render_offscreen thing affects it.
6843 * SetViewport may catch NOP viewport changes, which would occur when switching between equally sized targets
6845 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_VIEWPORT);
6847 return WINED3D_OK;
6850 static HRESULT WINAPI IWineD3DDeviceImpl_SetDepthStencilSurface(IWineD3DDevice *iface, IWineD3DSurface *pNewZStencil) {
6851 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
6852 HRESULT hr = WINED3D_OK;
6853 IWineD3DSurface *tmp;
6855 TRACE("(%p) Swapping z-buffer. Old = %p, new = %p\n",This, This->stencilBufferTarget, pNewZStencil);
6857 if (pNewZStencil == This->stencilBufferTarget) {
6858 TRACE("Trying to do a NOP SetRenderTarget operation\n");
6859 } else {
6860 /** OpenGL doesn't support 'sharing' of the stencilBuffer so we may incur an extra memory overhead
6861 * depending on the renter target implementation being used.
6862 * A shared context implementation will share all buffers between all rendertargets (including swapchains),
6863 * implementations that use separate pbuffers for different swapchains or rendertargets will have to duplicate the
6864 * stencil buffer and incur an extra memory overhead
6865 ******************************************************/
6867 if (This->stencilBufferTarget) {
6868 ActivateContext(This, This->render_targets[0], CTXUSAGE_RESOURCELOAD);
6869 surface_load_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6870 surface_modify_ds_location(This->stencilBufferTarget, SFLAG_DS_OFFSCREEN);
6873 tmp = This->stencilBufferTarget;
6874 This->stencilBufferTarget = pNewZStencil;
6875 /* should we be calling the parent or the wined3d surface? */
6876 if (NULL != This->stencilBufferTarget) IWineD3DSurface_AddRef(This->stencilBufferTarget);
6877 if (NULL != tmp) IWineD3DSurface_Release(tmp);
6878 hr = WINED3D_OK;
6880 if((!tmp && pNewZStencil) || (!pNewZStencil && tmp)) {
6881 /* Swapping NULL / non NULL depth stencil affects the depth and tests */
6882 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_ZENABLE));
6883 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILENABLE));
6884 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_RENDER(WINED3DRS_STENCILWRITEMASK));
6888 return hr;
6891 static HRESULT WINAPI IWineD3DDeviceImpl_SetCursorProperties(IWineD3DDevice* iface, UINT XHotSpot,
6892 UINT YHotSpot, IWineD3DSurface *pCursorBitmap) {
6893 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
6894 /* TODO: the use of Impl is deprecated. */
6895 IWineD3DSurfaceImpl * pSur = (IWineD3DSurfaceImpl *) pCursorBitmap;
6896 WINED3DLOCKED_RECT lockedRect;
6898 TRACE("(%p) : Spot Pos(%u,%u)\n", This, XHotSpot, YHotSpot);
6900 /* some basic validation checks */
6901 if(This->cursorTexture) {
6902 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
6903 ENTER_GL();
6904 glDeleteTextures(1, &This->cursorTexture);
6905 LEAVE_GL();
6906 This->cursorTexture = 0;
6909 if ( (pSur->currentDesc.Width == 32) && (pSur->currentDesc.Height == 32) )
6910 This->haveHardwareCursor = TRUE;
6911 else
6912 This->haveHardwareCursor = FALSE;
6914 if(pCursorBitmap) {
6915 WINED3DLOCKED_RECT rect;
6917 /* MSDN: Cursor must be A8R8G8B8 */
6918 if (WINED3DFMT_A8R8G8B8 != pSur->resource.format) {
6919 ERR("(%p) : surface(%p) has an invalid format\n", This, pCursorBitmap);
6920 return WINED3DERR_INVALIDCALL;
6923 /* MSDN: Cursor must be smaller than the display mode */
6924 if(pSur->currentDesc.Width > This->ddraw_width ||
6925 pSur->currentDesc.Height > This->ddraw_height) {
6926 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);
6927 return WINED3DERR_INVALIDCALL;
6930 if (!This->haveHardwareCursor) {
6931 /* TODO: MSDN: Cursor sizes must be a power of 2 */
6933 /* Do not store the surface's pointer because the application may
6934 * release it after setting the cursor image. Windows doesn't
6935 * addref the set surface, so we can't do this either without
6936 * creating circular refcount dependencies. Copy out the gl texture
6937 * instead.
6939 This->cursorWidth = pSur->currentDesc.Width;
6940 This->cursorHeight = pSur->currentDesc.Height;
6941 if (SUCCEEDED(IWineD3DSurface_LockRect(pCursorBitmap, &rect, NULL, WINED3DLOCK_READONLY)))
6943 const GlPixelFormatDesc *glDesc;
6944 const StaticPixelFormatDesc *tableEntry = getFormatDescEntry(WINED3DFMT_A8R8G8B8, &GLINFO_LOCATION, &glDesc);
6945 char *mem, *bits = (char *)rect.pBits;
6946 GLint intfmt = glDesc->glInternal;
6947 GLint format = glDesc->glFormat;
6948 GLint type = glDesc->glType;
6949 INT height = This->cursorHeight;
6950 INT width = This->cursorWidth;
6951 INT bpp = tableEntry->bpp;
6952 INT i, sampler;
6954 /* Reformat the texture memory (pitch and width can be
6955 * different) */
6956 mem = HeapAlloc(GetProcessHeap(), 0, width * height * bpp);
6957 for(i = 0; i < height; i++)
6958 memcpy(&mem[width * bpp * i], &bits[rect.Pitch * i], width * bpp);
6959 IWineD3DSurface_UnlockRect(pCursorBitmap);
6960 ENTER_GL();
6962 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6963 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE);
6964 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_FALSE)");
6967 /* Make sure that a proper texture unit is selected */
6968 if (GL_SUPPORT(ARB_MULTITEXTURE)) {
6969 GL_EXTCALL(glActiveTextureARB(GL_TEXTURE0_ARB));
6970 checkGLcall("glActiveTextureARB");
6972 sampler = This->rev_tex_unit_map[0];
6973 if (sampler != -1) {
6974 IWineD3DDeviceImpl_MarkStateDirty(This, STATE_SAMPLER(sampler));
6976 /* Create a new cursor texture */
6977 glGenTextures(1, &This->cursorTexture);
6978 checkGLcall("glGenTextures");
6979 glBindTexture(GL_TEXTURE_2D, This->cursorTexture);
6980 checkGLcall("glBindTexture");
6981 /* Copy the bitmap memory into the cursor texture */
6982 glTexImage2D(GL_TEXTURE_2D, 0, intfmt, width, height, 0, format, type, mem);
6983 HeapFree(GetProcessHeap(), 0, mem);
6984 checkGLcall("glTexImage2D");
6986 if(GL_SUPPORT(APPLE_CLIENT_STORAGE)) {
6987 glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);
6988 checkGLcall("glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE)");
6991 LEAVE_GL();
6993 else
6995 FIXME("A cursor texture was not returned.\n");
6996 This->cursorTexture = 0;
6999 else
7001 /* Draw a hardware cursor */
7002 ICONINFO cursorInfo;
7003 HCURSOR cursor;
7004 /* Create and clear maskBits because it is not needed for
7005 * 32-bit cursors. 32x32 bits split into 32-bit chunks == 32
7006 * chunks. */
7007 DWORD *maskBits = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
7008 (pSur->currentDesc.Width * pSur->currentDesc.Height / 8));
7009 IWineD3DSurface_LockRect(pCursorBitmap, &lockedRect, NULL,
7010 WINED3DLOCK_NO_DIRTY_UPDATE |
7011 WINED3DLOCK_READONLY
7013 TRACE("width: %i height: %i\n", pSur->currentDesc.Width,
7014 pSur->currentDesc.Height);
7016 cursorInfo.fIcon = FALSE;
7017 cursorInfo.xHotspot = XHotSpot;
7018 cursorInfo.yHotspot = YHotSpot;
7019 cursorInfo.hbmMask = CreateBitmap(pSur->currentDesc.Width,
7020 pSur->currentDesc.Height, 1,
7021 1, &maskBits);
7022 cursorInfo.hbmColor = CreateBitmap(pSur->currentDesc.Width,
7023 pSur->currentDesc.Height, 1,
7024 32, lockedRect.pBits);
7025 IWineD3DSurface_UnlockRect(pCursorBitmap);
7026 /* Create our cursor and clean up. */
7027 cursor = CreateIconIndirect(&cursorInfo);
7028 SetCursor(cursor);
7029 if (cursorInfo.hbmMask) DeleteObject(cursorInfo.hbmMask);
7030 if (cursorInfo.hbmColor) DeleteObject(cursorInfo.hbmColor);
7031 if (This->hardwareCursor) DestroyCursor(This->hardwareCursor);
7032 This->hardwareCursor = cursor;
7033 HeapFree(GetProcessHeap(), 0, maskBits);
7037 This->xHotSpot = XHotSpot;
7038 This->yHotSpot = YHotSpot;
7039 return WINED3D_OK;
7042 static void WINAPI IWineD3DDeviceImpl_SetCursorPosition(IWineD3DDevice* iface, int XScreenSpace, int YScreenSpace, DWORD Flags) {
7043 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7044 TRACE("(%p) : SetPos to (%u,%u)\n", This, XScreenSpace, YScreenSpace);
7046 This->xScreenSpace = XScreenSpace;
7047 This->yScreenSpace = YScreenSpace;
7049 return;
7053 static BOOL WINAPI IWineD3DDeviceImpl_ShowCursor(IWineD3DDevice* iface, BOOL bShow) {
7054 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7055 BOOL oldVisible = This->bCursorVisible;
7056 POINT pt;
7058 TRACE("(%p) : visible(%d)\n", This, bShow);
7061 * When ShowCursor is first called it should make the cursor appear at the OS's last
7062 * known cursor position. Because of this, some applications just repetitively call
7063 * ShowCursor in order to update the cursor's position. This behavior is undocumented.
7065 GetCursorPos(&pt);
7066 This->xScreenSpace = pt.x;
7067 This->yScreenSpace = pt.y;
7069 if (This->haveHardwareCursor) {
7070 This->bCursorVisible = bShow;
7071 if (bShow)
7072 SetCursor(This->hardwareCursor);
7073 else
7074 SetCursor(NULL);
7076 else
7078 if (This->cursorTexture)
7079 This->bCursorVisible = bShow;
7082 return oldVisible;
7085 static HRESULT WINAPI IWineD3DDeviceImpl_TestCooperativeLevel(IWineD3DDevice* iface) {
7086 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7087 IWineD3DResourceImpl *resource;
7088 TRACE("(%p) : state (%u)\n", This, This->state);
7090 /* TODO: Implement wrapping of the WndProc so that mimimize and maximize can be monitored and the states adjusted. */
7091 switch (This->state) {
7092 case WINED3D_OK:
7093 return WINED3D_OK;
7094 case WINED3DERR_DEVICELOST:
7096 LIST_FOR_EACH_ENTRY(resource, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7097 if (resource->resource.pool == WINED3DPOOL_DEFAULT)
7098 return WINED3DERR_DEVICENOTRESET;
7100 return WINED3DERR_DEVICELOST;
7102 case WINED3DERR_DRIVERINTERNALERROR:
7103 return WINED3DERR_DRIVERINTERNALERROR;
7106 /* Unknown state */
7107 return WINED3DERR_DRIVERINTERNALERROR;
7111 static HRESULT WINAPI IWineD3DDeviceImpl_EvictManagedResources(IWineD3DDevice* iface) {
7112 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7113 /** FIXME: Resource tracking needs to be done,
7114 * The closes we can do to this is set the priorities of all managed textures low
7115 * and then reset them.
7116 ***********************************************************/
7117 FIXME("(%p) : stub\n", This);
7118 return WINED3D_OK;
7121 static void updateSurfaceDesc(IWineD3DSurfaceImpl *surface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7122 IWineD3DDeviceImpl *This = surface->resource.wineD3DDevice; /* for GL_SUPPORT */
7124 /* Reallocate proper memory for the front and back buffer and adjust their sizes */
7125 if(surface->Flags & SFLAG_DIBSECTION) {
7126 /* Release the DC */
7127 SelectObject(surface->hDC, surface->dib.holdbitmap);
7128 DeleteDC(surface->hDC);
7129 /* Release the DIB section */
7130 DeleteObject(surface->dib.DIBsection);
7131 surface->dib.bitmap_data = NULL;
7132 surface->resource.allocatedMemory = NULL;
7133 surface->Flags &= ~SFLAG_DIBSECTION;
7135 surface->currentDesc.Width = pPresentationParameters->BackBufferWidth;
7136 surface->currentDesc.Height = pPresentationParameters->BackBufferHeight;
7137 if (GL_SUPPORT(ARB_TEXTURE_NON_POWER_OF_TWO) || GL_SUPPORT(ARB_TEXTURE_RECTANGLE) ||
7138 GL_SUPPORT(WINE_NORMALIZED_TEXRECT)) {
7139 surface->pow2Width = pPresentationParameters->BackBufferWidth;
7140 surface->pow2Height = pPresentationParameters->BackBufferHeight;
7141 } else {
7142 surface->pow2Width = surface->pow2Height = 1;
7143 while (surface->pow2Width < pPresentationParameters->BackBufferWidth) surface->pow2Width <<= 1;
7144 while (surface->pow2Height < pPresentationParameters->BackBufferHeight) surface->pow2Height <<= 1;
7146 surface->glRect.left = 0;
7147 surface->glRect.top = 0;
7148 surface->glRect.right = surface->pow2Width;
7149 surface->glRect.bottom = surface->pow2Height;
7151 if(surface->glDescription.textureName) {
7152 ActivateContext(This, This->lastActiveRenderTarget, CTXUSAGE_RESOURCELOAD);
7153 ENTER_GL();
7154 glDeleteTextures(1, &surface->glDescription.textureName);
7155 LEAVE_GL();
7156 surface->glDescription.textureName = 0;
7157 surface->Flags &= ~SFLAG_CLIENT;
7159 if(surface->pow2Width != pPresentationParameters->BackBufferWidth ||
7160 surface->pow2Height != pPresentationParameters->BackBufferHeight) {
7161 surface->Flags |= SFLAG_NONPOW2;
7162 } else {
7163 surface->Flags &= ~SFLAG_NONPOW2;
7165 HeapFree(GetProcessHeap(), 0, surface->resource.heapMemory);
7166 surface->resource.allocatedMemory = NULL;
7167 surface->resource.heapMemory = NULL;
7168 surface->resource.size = IWineD3DSurface_GetPitch((IWineD3DSurface *) surface) * surface->pow2Width;
7169 /* INDRAWABLE is a sane place for implicit targets after the reset, INSYSMEM is more appropriate for depth stencils. */
7170 if (surface->resource.usage & WINED3DUSAGE_DEPTHSTENCIL) {
7171 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INSYSMEM, TRUE);
7172 } else {
7173 IWineD3DSurface_ModifyLocation((IWineD3DSurface *) surface, SFLAG_INDRAWABLE, TRUE);
7177 static HRESULT WINAPI reset_unload_resources(IWineD3DResource *resource, void *data) {
7178 TRACE("Unloading resource %p\n", resource);
7179 IWineD3DResource_UnLoad(resource);
7180 IWineD3DResource_Release(resource);
7181 return S_OK;
7184 static BOOL is_display_mode_supported(IWineD3DDeviceImpl *This, WINED3DPRESENT_PARAMETERS *pp) {
7185 UINT i, count;
7186 WINED3DDISPLAYMODE m;
7187 HRESULT hr;
7189 /* All Windowed modes are supported, as is leaving the current mode */
7190 if(pp->Windowed) return TRUE;
7191 if(!pp->BackBufferWidth) return TRUE;
7192 if(!pp->BackBufferHeight) return TRUE;
7194 count = IWineD3D_GetAdapterModeCount(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN);
7195 for(i = 0; i < count; i++) {
7196 memset(&m, 0, sizeof(m));
7197 hr = IWineD3D_EnumAdapterModes(This->wineD3D, This->adapter->num, WINED3DFMT_UNKNOWN, i, &m);
7198 if(FAILED(hr)) {
7199 ERR("EnumAdapterModes failed\n");
7201 if(m.Width == pp->BackBufferWidth && m.Height == pp->BackBufferHeight) {
7202 /* Mode found, it is supported */
7203 return TRUE;
7206 /* Mode not found -> not supported */
7207 return FALSE;
7210 void delete_opengl_contexts(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7211 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7212 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7213 UINT i;
7214 IWineD3DBaseShaderImpl *shader;
7216 IWineD3DDevice_EnumResources(iface, reset_unload_resources, NULL);
7217 LIST_FOR_EACH_ENTRY(shader, &This->shaders, IWineD3DBaseShaderImpl, baseShader.shader_list_entry) {
7218 This->shader_backend->shader_destroy((IWineD3DBaseShader *) shader);
7221 ENTER_GL();
7222 if(This->depth_blt_texture) {
7223 glDeleteTextures(1, &This->depth_blt_texture);
7224 This->depth_blt_texture = 0;
7226 if (This->depth_blt_rb) {
7227 GL_EXTCALL(glDeleteRenderbuffersEXT(1, &This->depth_blt_rb));
7228 This->depth_blt_rb = 0;
7229 This->depth_blt_rb_w = 0;
7230 This->depth_blt_rb_h = 0;
7232 This->blitter->free_private(iface);
7233 This->frag_pipe->free_private(iface);
7234 This->shader_backend->shader_free_private(iface);
7236 for (i = 0; i < GL_LIMITS(textures); i++) {
7237 /* Textures are recreated below */
7238 glDeleteTextures(1, &This->dummyTextureName[i]);
7239 checkGLcall("glDeleteTextures(1, &This->dummyTextureName[i])");
7240 This->dummyTextureName[i] = 0;
7242 LEAVE_GL();
7244 while(This->numContexts) {
7245 DestroyContext(This, This->contexts[0]);
7247 This->activeContext = NULL;
7248 HeapFree(GetProcessHeap(), 0, swapchain->context);
7249 swapchain->context = NULL;
7250 swapchain->num_contexts = 0;
7253 HRESULT create_primary_opengl_context(IWineD3DDevice *iface, IWineD3DSwapChain *swapchain_iface) {
7254 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7255 IWineD3DSwapChainImpl *swapchain = (IWineD3DSwapChainImpl *) swapchain_iface;
7256 HRESULT hr;
7257 IWineD3DSurfaceImpl *target;
7259 /* Recreate the primary swapchain's context */
7260 swapchain->context = HeapAlloc(GetProcessHeap(), 0, sizeof(*swapchain->context));
7261 if(swapchain->backBuffer) {
7262 target = (IWineD3DSurfaceImpl *) swapchain->backBuffer[0];
7263 } else {
7264 target = (IWineD3DSurfaceImpl *) swapchain->frontBuffer;
7266 swapchain->context[0] = CreateContext(This, target, swapchain->win_handle, FALSE,
7267 &swapchain->presentParms);
7268 swapchain->num_contexts = 1;
7269 This->activeContext = swapchain->context[0];
7271 create_dummy_textures(This);
7273 hr = This->shader_backend->shader_alloc_private(iface);
7274 if(FAILED(hr)) {
7275 ERR("Failed to recreate shader private data\n");
7276 goto err_out;
7278 hr = This->frag_pipe->alloc_private(iface);
7279 if(FAILED(hr)) {
7280 TRACE("Fragment pipeline private data couldn't be allocated\n");
7281 goto err_out;
7283 hr = This->blitter->alloc_private(iface);
7284 if(FAILED(hr)) {
7285 TRACE("Blitter private data couldn't be allocated\n");
7286 goto err_out;
7289 return WINED3D_OK;
7291 err_out:
7292 This->blitter->free_private(iface);
7293 This->frag_pipe->free_private(iface);
7294 This->shader_backend->shader_free_private(iface);
7295 return hr;
7298 static HRESULT WINAPI IWineD3DDeviceImpl_Reset(IWineD3DDevice* iface, WINED3DPRESENT_PARAMETERS* pPresentationParameters) {
7299 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7300 IWineD3DSwapChainImpl *swapchain;
7301 HRESULT hr;
7302 BOOL DisplayModeChanged = FALSE;
7303 WINED3DDISPLAYMODE mode;
7304 TRACE("(%p)\n", This);
7306 hr = IWineD3DDevice_GetSwapChain(iface, 0, (IWineD3DSwapChain **) &swapchain);
7307 if(FAILED(hr)) {
7308 ERR("Failed to get the first implicit swapchain\n");
7309 return hr;
7312 if(!is_display_mode_supported(This, pPresentationParameters)) {
7313 WARN("Rejecting Reset() call because the requested display mode is not supported\n");
7314 WARN("Requested mode: %d, %d\n", pPresentationParameters->BackBufferWidth,
7315 pPresentationParameters->BackBufferHeight);
7316 return WINED3DERR_INVALIDCALL;
7319 /* Is it necessary to recreate the gl context? Actually every setting can be changed
7320 * on an existing gl context, so there's no real need for recreation.
7322 * TODO: Figure out how Reset influences resources in D3DPOOL_DEFAULT, D3DPOOL_SYSTEMMEMORY and D3DPOOL_MANAGED
7324 * TODO: Figure out what happens to explicit swapchains, or if we have more than one implicit swapchain
7326 TRACE("New params:\n");
7327 TRACE("BackBufferWidth = %d\n", pPresentationParameters->BackBufferWidth);
7328 TRACE("BackBufferHeight = %d\n", pPresentationParameters->BackBufferHeight);
7329 TRACE("BackBufferFormat = %s\n", debug_d3dformat(pPresentationParameters->BackBufferFormat));
7330 TRACE("BackBufferCount = %d\n", pPresentationParameters->BackBufferCount);
7331 TRACE("MultiSampleType = %d\n", pPresentationParameters->MultiSampleType);
7332 TRACE("MultiSampleQuality = %d\n", pPresentationParameters->MultiSampleQuality);
7333 TRACE("SwapEffect = %d\n", pPresentationParameters->SwapEffect);
7334 TRACE("hDeviceWindow = %p\n", pPresentationParameters->hDeviceWindow);
7335 TRACE("Windowed = %s\n", pPresentationParameters->Windowed ? "true" : "false");
7336 TRACE("EnableAutoDepthStencil = %s\n", pPresentationParameters->EnableAutoDepthStencil ? "true" : "false");
7337 TRACE("Flags = %08x\n", pPresentationParameters->Flags);
7338 TRACE("FullScreen_RefreshRateInHz = %d\n", pPresentationParameters->FullScreen_RefreshRateInHz);
7339 TRACE("PresentationInterval = %d\n", pPresentationParameters->PresentationInterval);
7341 /* No special treatment of these parameters. Just store them */
7342 swapchain->presentParms.SwapEffect = pPresentationParameters->SwapEffect;
7343 swapchain->presentParms.Flags = pPresentationParameters->Flags;
7344 swapchain->presentParms.PresentationInterval = pPresentationParameters->PresentationInterval;
7345 swapchain->presentParms.FullScreen_RefreshRateInHz = pPresentationParameters->FullScreen_RefreshRateInHz;
7347 /* What to do about these? */
7348 if(pPresentationParameters->BackBufferCount != 0 &&
7349 pPresentationParameters->BackBufferCount != swapchain->presentParms.BackBufferCount) {
7350 ERR("Cannot change the back buffer count yet\n");
7352 if(pPresentationParameters->BackBufferFormat != WINED3DFMT_UNKNOWN &&
7353 pPresentationParameters->BackBufferFormat != swapchain->presentParms.BackBufferFormat) {
7354 ERR("Cannot change the back buffer format yet\n");
7356 if(pPresentationParameters->hDeviceWindow != NULL &&
7357 pPresentationParameters->hDeviceWindow != swapchain->presentParms.hDeviceWindow) {
7358 ERR("Cannot change the device window yet\n");
7360 if (pPresentationParameters->EnableAutoDepthStencil && !This->auto_depth_stencil_buffer) {
7361 WARN("Auto depth stencil enabled, but no auto depth stencil present, returning WINED3DERR_INVALIDCALL\n");
7362 return WINED3DERR_INVALIDCALL;
7365 /* Reset the depth stencil */
7366 if (pPresentationParameters->EnableAutoDepthStencil)
7367 IWineD3DDevice_SetDepthStencilSurface(iface, This->auto_depth_stencil_buffer);
7368 else
7369 IWineD3DDevice_SetDepthStencilSurface(iface, NULL);
7371 delete_opengl_contexts(iface, (IWineD3DSwapChain *) swapchain);
7373 if(pPresentationParameters->Windowed) {
7374 mode.Width = swapchain->orig_width;
7375 mode.Height = swapchain->orig_height;
7376 mode.RefreshRate = 0;
7377 mode.Format = swapchain->presentParms.BackBufferFormat;
7378 } else {
7379 mode.Width = pPresentationParameters->BackBufferWidth;
7380 mode.Height = pPresentationParameters->BackBufferHeight;
7381 mode.RefreshRate = pPresentationParameters->FullScreen_RefreshRateInHz;
7382 mode.Format = swapchain->presentParms.BackBufferFormat;
7385 /* Should Width == 800 && Height == 0 set 800x600? */
7386 if(pPresentationParameters->BackBufferWidth != 0 && pPresentationParameters->BackBufferHeight != 0 &&
7387 (pPresentationParameters->BackBufferWidth != swapchain->presentParms.BackBufferWidth ||
7388 pPresentationParameters->BackBufferHeight != swapchain->presentParms.BackBufferHeight))
7390 WINED3DVIEWPORT vp;
7391 int i;
7393 vp.X = 0;
7394 vp.Y = 0;
7395 vp.Width = pPresentationParameters->BackBufferWidth;
7396 vp.Height = pPresentationParameters->BackBufferHeight;
7397 vp.MinZ = 0;
7398 vp.MaxZ = 1;
7400 if(!pPresentationParameters->Windowed) {
7401 DisplayModeChanged = TRUE;
7403 swapchain->presentParms.BackBufferWidth = pPresentationParameters->BackBufferWidth;
7404 swapchain->presentParms.BackBufferHeight = pPresentationParameters->BackBufferHeight;
7406 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->frontBuffer, pPresentationParameters);
7407 for(i = 0; i < swapchain->presentParms.BackBufferCount; i++) {
7408 updateSurfaceDesc((IWineD3DSurfaceImpl *)swapchain->backBuffer[i], pPresentationParameters);
7410 if(This->auto_depth_stencil_buffer) {
7411 updateSurfaceDesc((IWineD3DSurfaceImpl *)This->auto_depth_stencil_buffer, pPresentationParameters);
7415 /* Now set the new viewport */
7416 IWineD3DDevice_SetViewport(iface, &vp);
7419 if((pPresentationParameters->Windowed && !swapchain->presentParms.Windowed) ||
7420 (swapchain->presentParms.Windowed && !pPresentationParameters->Windowed) ||
7421 DisplayModeChanged) {
7423 IWineD3DDevice_SetDisplayMode(iface, 0, &mode);
7425 if(swapchain->win_handle && !pPresentationParameters->Windowed) {
7426 if(swapchain->presentParms.Windowed) {
7427 /* switch from windowed to fs */
7428 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7429 pPresentationParameters->BackBufferWidth,
7430 pPresentationParameters->BackBufferHeight);
7431 } else {
7432 /* Fullscreen -> fullscreen mode change */
7433 MoveWindow(swapchain->win_handle, 0, 0,
7434 pPresentationParameters->BackBufferWidth, pPresentationParameters->BackBufferHeight,
7435 TRUE);
7437 } else if(swapchain->win_handle && !swapchain->presentParms.Windowed) {
7438 /* Fullscreen -> windowed switch */
7439 IWineD3DDeviceImpl_RestoreWindow(iface, swapchain->win_handle);
7441 swapchain->presentParms.Windowed = pPresentationParameters->Windowed;
7442 } else if(!pPresentationParameters->Windowed) {
7443 DWORD style = This->style, exStyle = This->exStyle;
7444 /* If we're in fullscreen, and the mode wasn't changed, we have to get the window back into
7445 * the right position. Some applications(Battlefield 2, Guild Wars) move it and then call
7446 * Reset to clear up their mess. Guild Wars also loses the device during that.
7448 This->style = 0;
7449 This->exStyle = 0;
7450 IWineD3DDeviceImpl_SetupFullscreenWindow(iface, swapchain->win_handle,
7451 pPresentationParameters->BackBufferWidth,
7452 pPresentationParameters->BackBufferHeight);
7453 This->style = style;
7454 This->exStyle = exStyle;
7457 hr = IWineD3DStateBlock_InitStartupStateBlock((IWineD3DStateBlock *) This->stateBlock);
7458 if(FAILED(hr)) {
7459 ERR("Resetting the stateblock failed with error 0x%08x\n", hr);
7462 hr = create_primary_opengl_context(iface, (IWineD3DSwapChain *) swapchain);
7463 IWineD3DSwapChain_Release((IWineD3DSwapChain *) swapchain);
7465 /* All done. There is no need to reload resources or shaders, this will happen automatically on the
7466 * first use
7468 return hr;
7471 static HRESULT WINAPI IWineD3DDeviceImpl_SetDialogBoxMode(IWineD3DDevice *iface, BOOL bEnableDialogs) {
7472 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7473 /** FIXME: always true at the moment **/
7474 if(!bEnableDialogs) {
7475 FIXME("(%p) Dialogs cannot be disabled yet\n", This);
7477 return WINED3D_OK;
7481 static HRESULT WINAPI IWineD3DDeviceImpl_GetCreationParameters(IWineD3DDevice *iface, WINED3DDEVICE_CREATION_PARAMETERS *pParameters) {
7482 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7483 TRACE("(%p) : pParameters %p\n", This, pParameters);
7485 *pParameters = This->createParms;
7486 return WINED3D_OK;
7489 static void WINAPI IWineD3DDeviceImpl_SetGammaRamp(IWineD3DDevice * iface, UINT iSwapChain, DWORD Flags, CONST WINED3DGAMMARAMP* pRamp) {
7490 IWineD3DSwapChain *swapchain;
7492 TRACE("Relaying to swapchain\n");
7494 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7495 IWineD3DSwapChain_SetGammaRamp(swapchain, Flags, (WINED3DGAMMARAMP *)pRamp);
7496 IWineD3DSwapChain_Release(swapchain);
7498 return;
7501 static void WINAPI IWineD3DDeviceImpl_GetGammaRamp(IWineD3DDevice *iface, UINT iSwapChain, WINED3DGAMMARAMP* pRamp) {
7502 IWineD3DSwapChain *swapchain;
7504 TRACE("Relaying to swapchain\n");
7506 if (IWineD3DDeviceImpl_GetSwapChain(iface, iSwapChain, &swapchain) == WINED3D_OK) {
7507 IWineD3DSwapChain_GetGammaRamp(swapchain, pRamp);
7508 IWineD3DSwapChain_Release(swapchain);
7510 return;
7514 /** ********************************************************
7515 * Notification functions
7516 ** ********************************************************/
7517 /** This function must be called in the release of a resource when ref == 0,
7518 * the contents of resource must still be correct,
7519 * any handles to other resource held by the caller must be closed
7520 * (e.g. a texture should release all held surfaces because telling the device that it's been released.)
7521 *****************************************************/
7522 static void WINAPI IWineD3DDeviceImpl_AddResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7523 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7525 TRACE("(%p) : Adding Resource %p\n", This, resource);
7526 list_add_head(&This->resources, &((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7529 static void WINAPI IWineD3DDeviceImpl_RemoveResource(IWineD3DDevice *iface, IWineD3DResource *resource){
7530 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *)iface;
7532 TRACE("(%p) : Removing resource %p\n", This, resource);
7534 list_remove(&((IWineD3DResourceImpl *) resource)->resource.resource_list_entry);
7538 static void WINAPI IWineD3DDeviceImpl_ResourceReleased(IWineD3DDevice *iface, IWineD3DResource *resource){
7539 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7540 int counter;
7542 TRACE("(%p) : resource %p\n", This, resource);
7543 switch(IWineD3DResource_GetType(resource)){
7544 /* TODO: check front and back buffers, rendertargets etc.. possibly swapchains? */
7545 case WINED3DRTYPE_SURFACE: {
7546 unsigned int i;
7548 /* Cleanup any FBO attachments if d3d is enabled */
7549 if(This->d3d_initialized) {
7550 if((IWineD3DSurface *)resource == This->lastActiveRenderTarget) {
7551 IWineD3DSwapChainImpl *swapchain = This->swapchains ? (IWineD3DSwapChainImpl *) This->swapchains[0] : NULL;
7553 TRACE("Last active render target destroyed\n");
7554 /* Find a replacement surface for the currently active back buffer. The context manager does not do NULL
7555 * checks, so switch to a valid target as long as the currently set surface is still valid. Use the
7556 * surface of the implicit swpchain. If that is the same as the destroyed surface the device is destroyed
7557 * and the lastActiveRenderTarget member shouldn't matter
7559 if(swapchain) {
7560 if(swapchain->backBuffer && swapchain->backBuffer[0] != (IWineD3DSurface *)resource) {
7561 TRACE("Activating primary back buffer\n");
7562 ActivateContext(This, swapchain->backBuffer[0], CTXUSAGE_RESOURCELOAD);
7563 } else if(!swapchain->backBuffer && swapchain->frontBuffer != (IWineD3DSurface *)resource) {
7564 /* Single buffering environment */
7565 TRACE("Activating primary front buffer\n");
7566 ActivateContext(This, swapchain->frontBuffer, CTXUSAGE_RESOURCELOAD);
7567 } else {
7568 TRACE("Device is being destroyed, setting lastActiveRenderTarget = 0xdeadbabe\n");
7569 /* Implicit render target destroyed, that means the device is being destroyed
7570 * whatever we set here, it shouldn't matter
7572 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadbabe;
7574 } else {
7575 /* May happen during ddraw uninitialization */
7576 TRACE("Render target set, but swapchain does not exist!\n");
7577 This->lastActiveRenderTarget = (IWineD3DSurface *) 0xdeadcafe;
7581 for (i = 0; i < GL_LIMITS(buffers); ++i) {
7582 if (This->render_targets[i] == (IWineD3DSurface *)resource) {
7583 This->render_targets[i] = NULL;
7586 if (This->stencilBufferTarget == (IWineD3DSurface *)resource) {
7587 This->stencilBufferTarget = NULL;
7590 for (i = 0; i < This->numContexts; ++i) {
7591 int j;
7592 for (j = 0; j < GL_LIMITS(buffers); ++j) {
7593 if (This->contexts[i]->fbo_color_attachments[j] == (IWineD3DSurface *)resource) {
7594 This->contexts[i]->fbo_color_attachments[j] = NULL;
7597 if (This->contexts[i]->fbo_depth_attachment == (IWineD3DSurface *)resource) {
7598 This->contexts[i]->fbo_depth_attachment = NULL;
7603 break;
7605 case WINED3DRTYPE_TEXTURE:
7606 case WINED3DRTYPE_CUBETEXTURE:
7607 case WINED3DRTYPE_VOLUMETEXTURE:
7608 for (counter = 0; counter < MAX_COMBINED_SAMPLERS; counter++) {
7609 if (This->stateBlock != NULL && This->stateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7610 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7611 This->stateBlock->textures[counter] = NULL;
7613 if (This->updateStateBlock != This->stateBlock ){
7614 if (This->updateStateBlock->textures[counter] == (IWineD3DBaseTexture *)resource) {
7615 WARN("Texture being released is still by a stateblock, Stage = %u Texture = %p\n", counter, resource);
7616 This->updateStateBlock->textures[counter] = NULL;
7620 break;
7621 case WINED3DRTYPE_VOLUME:
7622 /* TODO: nothing really? */
7623 break;
7624 case WINED3DRTYPE_VERTEXBUFFER:
7625 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed. */
7627 int streamNumber;
7628 TRACE("Cleaning up stream pointers\n");
7630 for(streamNumber = 0; streamNumber < MAX_STREAMS; streamNumber ++){
7631 /* FINDOUT: should a warn be generated if were recording and updateStateBlock->streamSource is lost?
7632 FINDOUT: should changes.streamSource[StreamNumber] be set ?
7634 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7635 if ((IWineD3DResource *)This->updateStateBlock->streamSource[streamNumber] == resource) {
7636 FIXME("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7637 This->updateStateBlock->streamSource[streamNumber] = 0;
7638 /* Set changed flag? */
7641 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) */
7642 if ((IWineD3DResource *)This->stateBlock->streamSource[streamNumber] == resource) {
7643 TRACE("Vertex buffer released while bound to a state block, stream %d\n", streamNumber);
7644 This->stateBlock->streamSource[streamNumber] = 0;
7649 break;
7650 case WINED3DRTYPE_INDEXBUFFER:
7651 /* MSDN: When an application no longer holds a references to this interface, the interface will automatically be freed.*/
7652 if (This->updateStateBlock != NULL ) { /* ==NULL when device is being destroyed */
7653 if (This->updateStateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7654 This->updateStateBlock->pIndexData = NULL;
7657 if (This->stateBlock != NULL ) { /* ==NULL when device is being destroyed */
7658 if (This->stateBlock->pIndexData == (IWineD3DIndexBuffer *)resource) {
7659 This->stateBlock->pIndexData = NULL;
7663 break;
7664 default:
7665 FIXME("(%p) unknown resource type %p %u\n", This, resource, IWineD3DResource_GetType(resource));
7666 break;
7670 /* Remove the resource from the resourceStore */
7671 IWineD3DDeviceImpl_RemoveResource(iface, resource);
7673 TRACE("Resource released\n");
7677 static HRESULT WINAPI IWineD3DDeviceImpl_EnumResources(IWineD3DDevice *iface, D3DCB_ENUMRESOURCES pCallback, void *pData) {
7678 IWineD3DDeviceImpl *This = (IWineD3DDeviceImpl *) iface;
7679 IWineD3DResourceImpl *resource, *cursor;
7680 HRESULT ret;
7681 TRACE("(%p)->(%p,%p)\n", This, pCallback, pData);
7683 LIST_FOR_EACH_ENTRY_SAFE(resource, cursor, &This->resources, IWineD3DResourceImpl, resource.resource_list_entry) {
7684 TRACE("enumerating resource %p\n", resource);
7685 IWineD3DResource_AddRef((IWineD3DResource *) resource);
7686 ret = pCallback((IWineD3DResource *) resource, pData);
7687 if(ret == S_FALSE) {
7688 TRACE("Canceling enumeration\n");
7689 break;
7692 return WINED3D_OK;
7695 /**********************************************************
7696 * IWineD3DDevice VTbl follows
7697 **********************************************************/
7699 const IWineD3DDeviceVtbl IWineD3DDevice_Vtbl =
7701 /*** IUnknown methods ***/
7702 IWineD3DDeviceImpl_QueryInterface,
7703 IWineD3DDeviceImpl_AddRef,
7704 IWineD3DDeviceImpl_Release,
7705 /*** IWineD3DDevice methods ***/
7706 IWineD3DDeviceImpl_GetParent,
7707 /*** Creation methods**/
7708 IWineD3DDeviceImpl_CreateVertexBuffer,
7709 IWineD3DDeviceImpl_CreateIndexBuffer,
7710 IWineD3DDeviceImpl_CreateStateBlock,
7711 IWineD3DDeviceImpl_CreateSurface,
7712 IWineD3DDeviceImpl_CreateTexture,
7713 IWineD3DDeviceImpl_CreateVolumeTexture,
7714 IWineD3DDeviceImpl_CreateVolume,
7715 IWineD3DDeviceImpl_CreateCubeTexture,
7716 IWineD3DDeviceImpl_CreateQuery,
7717 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7718 IWineD3DDeviceImpl_CreateVertexDeclaration,
7719 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7720 IWineD3DDeviceImpl_CreateVertexShader,
7721 IWineD3DDeviceImpl_CreatePixelShader,
7722 IWineD3DDeviceImpl_CreatePalette,
7723 /*** Odd functions **/
7724 IWineD3DDeviceImpl_Init3D,
7725 IWineD3DDeviceImpl_InitGDI,
7726 IWineD3DDeviceImpl_Uninit3D,
7727 IWineD3DDeviceImpl_UninitGDI,
7728 IWineD3DDeviceImpl_SetMultithreaded,
7729 IWineD3DDeviceImpl_EvictManagedResources,
7730 IWineD3DDeviceImpl_GetAvailableTextureMem,
7731 IWineD3DDeviceImpl_GetBackBuffer,
7732 IWineD3DDeviceImpl_GetCreationParameters,
7733 IWineD3DDeviceImpl_GetDeviceCaps,
7734 IWineD3DDeviceImpl_GetDirect3D,
7735 IWineD3DDeviceImpl_GetDisplayMode,
7736 IWineD3DDeviceImpl_SetDisplayMode,
7737 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7738 IWineD3DDeviceImpl_GetRasterStatus,
7739 IWineD3DDeviceImpl_GetSwapChain,
7740 IWineD3DDeviceImpl_Reset,
7741 IWineD3DDeviceImpl_SetDialogBoxMode,
7742 IWineD3DDeviceImpl_SetCursorProperties,
7743 IWineD3DDeviceImpl_SetCursorPosition,
7744 IWineD3DDeviceImpl_ShowCursor,
7745 IWineD3DDeviceImpl_TestCooperativeLevel,
7746 /*** Getters and setters **/
7747 IWineD3DDeviceImpl_SetClipPlane,
7748 IWineD3DDeviceImpl_GetClipPlane,
7749 IWineD3DDeviceImpl_SetClipStatus,
7750 IWineD3DDeviceImpl_GetClipStatus,
7751 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7752 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7753 IWineD3DDeviceImpl_SetDepthStencilSurface,
7754 IWineD3DDeviceImpl_GetDepthStencilSurface,
7755 IWineD3DDeviceImpl_SetFVF,
7756 IWineD3DDeviceImpl_GetFVF,
7757 IWineD3DDeviceImpl_SetGammaRamp,
7758 IWineD3DDeviceImpl_GetGammaRamp,
7759 IWineD3DDeviceImpl_SetIndices,
7760 IWineD3DDeviceImpl_GetIndices,
7761 IWineD3DDeviceImpl_SetBaseVertexIndex,
7762 IWineD3DDeviceImpl_GetBaseVertexIndex,
7763 IWineD3DDeviceImpl_SetLight,
7764 IWineD3DDeviceImpl_GetLight,
7765 IWineD3DDeviceImpl_SetLightEnable,
7766 IWineD3DDeviceImpl_GetLightEnable,
7767 IWineD3DDeviceImpl_SetMaterial,
7768 IWineD3DDeviceImpl_GetMaterial,
7769 IWineD3DDeviceImpl_SetNPatchMode,
7770 IWineD3DDeviceImpl_GetNPatchMode,
7771 IWineD3DDeviceImpl_SetPaletteEntries,
7772 IWineD3DDeviceImpl_GetPaletteEntries,
7773 IWineD3DDeviceImpl_SetPixelShader,
7774 IWineD3DDeviceImpl_GetPixelShader,
7775 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7776 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7777 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7778 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7779 IWineD3DDeviceImpl_SetPixelShaderConstantF,
7780 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7781 IWineD3DDeviceImpl_SetRenderState,
7782 IWineD3DDeviceImpl_GetRenderState,
7783 IWineD3DDeviceImpl_SetRenderTarget,
7784 IWineD3DDeviceImpl_GetRenderTarget,
7785 IWineD3DDeviceImpl_SetFrontBackBuffers,
7786 IWineD3DDeviceImpl_SetSamplerState,
7787 IWineD3DDeviceImpl_GetSamplerState,
7788 IWineD3DDeviceImpl_SetScissorRect,
7789 IWineD3DDeviceImpl_GetScissorRect,
7790 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7791 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7792 IWineD3DDeviceImpl_SetStreamSource,
7793 IWineD3DDeviceImpl_GetStreamSource,
7794 IWineD3DDeviceImpl_SetStreamSourceFreq,
7795 IWineD3DDeviceImpl_GetStreamSourceFreq,
7796 IWineD3DDeviceImpl_SetTexture,
7797 IWineD3DDeviceImpl_GetTexture,
7798 IWineD3DDeviceImpl_SetTextureStageState,
7799 IWineD3DDeviceImpl_GetTextureStageState,
7800 IWineD3DDeviceImpl_SetTransform,
7801 IWineD3DDeviceImpl_GetTransform,
7802 IWineD3DDeviceImpl_SetVertexDeclaration,
7803 IWineD3DDeviceImpl_GetVertexDeclaration,
7804 IWineD3DDeviceImpl_SetVertexShader,
7805 IWineD3DDeviceImpl_GetVertexShader,
7806 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7807 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7808 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7809 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7810 IWineD3DDeviceImpl_SetVertexShaderConstantF,
7811 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7812 IWineD3DDeviceImpl_SetViewport,
7813 IWineD3DDeviceImpl_GetViewport,
7814 IWineD3DDeviceImpl_MultiplyTransform,
7815 IWineD3DDeviceImpl_ValidateDevice,
7816 IWineD3DDeviceImpl_ProcessVertices,
7817 /*** State block ***/
7818 IWineD3DDeviceImpl_BeginStateBlock,
7819 IWineD3DDeviceImpl_EndStateBlock,
7820 /*** Scene management ***/
7821 IWineD3DDeviceImpl_BeginScene,
7822 IWineD3DDeviceImpl_EndScene,
7823 IWineD3DDeviceImpl_Present,
7824 IWineD3DDeviceImpl_Clear,
7825 /*** Drawing ***/
7826 IWineD3DDeviceImpl_DrawPrimitive,
7827 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7828 IWineD3DDeviceImpl_DrawPrimitiveUP,
7829 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7830 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7831 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7832 IWineD3DDeviceImpl_DrawRectPatch,
7833 IWineD3DDeviceImpl_DrawTriPatch,
7834 IWineD3DDeviceImpl_DeletePatch,
7835 IWineD3DDeviceImpl_ColorFill,
7836 IWineD3DDeviceImpl_UpdateTexture,
7837 IWineD3DDeviceImpl_UpdateSurface,
7838 IWineD3DDeviceImpl_GetFrontBufferData,
7839 /*** object tracking ***/
7840 IWineD3DDeviceImpl_ResourceReleased,
7841 IWineD3DDeviceImpl_EnumResources
7844 const IWineD3DDeviceVtbl IWineD3DDevice_DirtyConst_Vtbl =
7846 /*** IUnknown methods ***/
7847 IWineD3DDeviceImpl_QueryInterface,
7848 IWineD3DDeviceImpl_AddRef,
7849 IWineD3DDeviceImpl_Release,
7850 /*** IWineD3DDevice methods ***/
7851 IWineD3DDeviceImpl_GetParent,
7852 /*** Creation methods**/
7853 IWineD3DDeviceImpl_CreateVertexBuffer,
7854 IWineD3DDeviceImpl_CreateIndexBuffer,
7855 IWineD3DDeviceImpl_CreateStateBlock,
7856 IWineD3DDeviceImpl_CreateSurface,
7857 IWineD3DDeviceImpl_CreateTexture,
7858 IWineD3DDeviceImpl_CreateVolumeTexture,
7859 IWineD3DDeviceImpl_CreateVolume,
7860 IWineD3DDeviceImpl_CreateCubeTexture,
7861 IWineD3DDeviceImpl_CreateQuery,
7862 IWineD3DDeviceImpl_CreateAdditionalSwapChain,
7863 IWineD3DDeviceImpl_CreateVertexDeclaration,
7864 IWineD3DDeviceImpl_CreateVertexDeclarationFromFVF,
7865 IWineD3DDeviceImpl_CreateVertexShader,
7866 IWineD3DDeviceImpl_CreatePixelShader,
7867 IWineD3DDeviceImpl_CreatePalette,
7868 /*** Odd functions **/
7869 IWineD3DDeviceImpl_Init3D,
7870 IWineD3DDeviceImpl_InitGDI,
7871 IWineD3DDeviceImpl_Uninit3D,
7872 IWineD3DDeviceImpl_UninitGDI,
7873 IWineD3DDeviceImpl_SetMultithreaded,
7874 IWineD3DDeviceImpl_EvictManagedResources,
7875 IWineD3DDeviceImpl_GetAvailableTextureMem,
7876 IWineD3DDeviceImpl_GetBackBuffer,
7877 IWineD3DDeviceImpl_GetCreationParameters,
7878 IWineD3DDeviceImpl_GetDeviceCaps,
7879 IWineD3DDeviceImpl_GetDirect3D,
7880 IWineD3DDeviceImpl_GetDisplayMode,
7881 IWineD3DDeviceImpl_SetDisplayMode,
7882 IWineD3DDeviceImpl_GetNumberOfSwapChains,
7883 IWineD3DDeviceImpl_GetRasterStatus,
7884 IWineD3DDeviceImpl_GetSwapChain,
7885 IWineD3DDeviceImpl_Reset,
7886 IWineD3DDeviceImpl_SetDialogBoxMode,
7887 IWineD3DDeviceImpl_SetCursorProperties,
7888 IWineD3DDeviceImpl_SetCursorPosition,
7889 IWineD3DDeviceImpl_ShowCursor,
7890 IWineD3DDeviceImpl_TestCooperativeLevel,
7891 /*** Getters and setters **/
7892 IWineD3DDeviceImpl_SetClipPlane,
7893 IWineD3DDeviceImpl_GetClipPlane,
7894 IWineD3DDeviceImpl_SetClipStatus,
7895 IWineD3DDeviceImpl_GetClipStatus,
7896 IWineD3DDeviceImpl_SetCurrentTexturePalette,
7897 IWineD3DDeviceImpl_GetCurrentTexturePalette,
7898 IWineD3DDeviceImpl_SetDepthStencilSurface,
7899 IWineD3DDeviceImpl_GetDepthStencilSurface,
7900 IWineD3DDeviceImpl_SetFVF,
7901 IWineD3DDeviceImpl_GetFVF,
7902 IWineD3DDeviceImpl_SetGammaRamp,
7903 IWineD3DDeviceImpl_GetGammaRamp,
7904 IWineD3DDeviceImpl_SetIndices,
7905 IWineD3DDeviceImpl_GetIndices,
7906 IWineD3DDeviceImpl_SetBaseVertexIndex,
7907 IWineD3DDeviceImpl_GetBaseVertexIndex,
7908 IWineD3DDeviceImpl_SetLight,
7909 IWineD3DDeviceImpl_GetLight,
7910 IWineD3DDeviceImpl_SetLightEnable,
7911 IWineD3DDeviceImpl_GetLightEnable,
7912 IWineD3DDeviceImpl_SetMaterial,
7913 IWineD3DDeviceImpl_GetMaterial,
7914 IWineD3DDeviceImpl_SetNPatchMode,
7915 IWineD3DDeviceImpl_GetNPatchMode,
7916 IWineD3DDeviceImpl_SetPaletteEntries,
7917 IWineD3DDeviceImpl_GetPaletteEntries,
7918 IWineD3DDeviceImpl_SetPixelShader,
7919 IWineD3DDeviceImpl_GetPixelShader,
7920 IWineD3DDeviceImpl_SetPixelShaderConstantB,
7921 IWineD3DDeviceImpl_GetPixelShaderConstantB,
7922 IWineD3DDeviceImpl_SetPixelShaderConstantI,
7923 IWineD3DDeviceImpl_GetPixelShaderConstantI,
7924 IWineD3DDeviceImpl_SetPixelShaderConstantF_DirtyConst,
7925 IWineD3DDeviceImpl_GetPixelShaderConstantF,
7926 IWineD3DDeviceImpl_SetRenderState,
7927 IWineD3DDeviceImpl_GetRenderState,
7928 IWineD3DDeviceImpl_SetRenderTarget,
7929 IWineD3DDeviceImpl_GetRenderTarget,
7930 IWineD3DDeviceImpl_SetFrontBackBuffers,
7931 IWineD3DDeviceImpl_SetSamplerState,
7932 IWineD3DDeviceImpl_GetSamplerState,
7933 IWineD3DDeviceImpl_SetScissorRect,
7934 IWineD3DDeviceImpl_GetScissorRect,
7935 IWineD3DDeviceImpl_SetSoftwareVertexProcessing,
7936 IWineD3DDeviceImpl_GetSoftwareVertexProcessing,
7937 IWineD3DDeviceImpl_SetStreamSource,
7938 IWineD3DDeviceImpl_GetStreamSource,
7939 IWineD3DDeviceImpl_SetStreamSourceFreq,
7940 IWineD3DDeviceImpl_GetStreamSourceFreq,
7941 IWineD3DDeviceImpl_SetTexture,
7942 IWineD3DDeviceImpl_GetTexture,
7943 IWineD3DDeviceImpl_SetTextureStageState,
7944 IWineD3DDeviceImpl_GetTextureStageState,
7945 IWineD3DDeviceImpl_SetTransform,
7946 IWineD3DDeviceImpl_GetTransform,
7947 IWineD3DDeviceImpl_SetVertexDeclaration,
7948 IWineD3DDeviceImpl_GetVertexDeclaration,
7949 IWineD3DDeviceImpl_SetVertexShader,
7950 IWineD3DDeviceImpl_GetVertexShader,
7951 IWineD3DDeviceImpl_SetVertexShaderConstantB,
7952 IWineD3DDeviceImpl_GetVertexShaderConstantB,
7953 IWineD3DDeviceImpl_SetVertexShaderConstantI,
7954 IWineD3DDeviceImpl_GetVertexShaderConstantI,
7955 IWineD3DDeviceImpl_SetVertexShaderConstantF_DirtyConst,
7956 IWineD3DDeviceImpl_GetVertexShaderConstantF,
7957 IWineD3DDeviceImpl_SetViewport,
7958 IWineD3DDeviceImpl_GetViewport,
7959 IWineD3DDeviceImpl_MultiplyTransform,
7960 IWineD3DDeviceImpl_ValidateDevice,
7961 IWineD3DDeviceImpl_ProcessVertices,
7962 /*** State block ***/
7963 IWineD3DDeviceImpl_BeginStateBlock,
7964 IWineD3DDeviceImpl_EndStateBlock,
7965 /*** Scene management ***/
7966 IWineD3DDeviceImpl_BeginScene,
7967 IWineD3DDeviceImpl_EndScene,
7968 IWineD3DDeviceImpl_Present,
7969 IWineD3DDeviceImpl_Clear,
7970 /*** Drawing ***/
7971 IWineD3DDeviceImpl_DrawPrimitive,
7972 IWineD3DDeviceImpl_DrawIndexedPrimitive,
7973 IWineD3DDeviceImpl_DrawPrimitiveUP,
7974 IWineD3DDeviceImpl_DrawIndexedPrimitiveUP,
7975 IWineD3DDeviceImpl_DrawPrimitiveStrided,
7976 IWineD3DDeviceImpl_DrawIndexedPrimitiveStrided,
7977 IWineD3DDeviceImpl_DrawRectPatch,
7978 IWineD3DDeviceImpl_DrawTriPatch,
7979 IWineD3DDeviceImpl_DeletePatch,
7980 IWineD3DDeviceImpl_ColorFill,
7981 IWineD3DDeviceImpl_UpdateTexture,
7982 IWineD3DDeviceImpl_UpdateSurface,
7983 IWineD3DDeviceImpl_GetFrontBufferData,
7984 /*** object tracking ***/
7985 IWineD3DDeviceImpl_ResourceReleased,
7986 IWineD3DDeviceImpl_EnumResources
7989 const DWORD SavedPixelStates_R[NUM_SAVEDPIXELSTATES_R] = {
7990 WINED3DRS_ALPHABLENDENABLE ,
7991 WINED3DRS_ALPHAFUNC ,
7992 WINED3DRS_ALPHAREF ,
7993 WINED3DRS_ALPHATESTENABLE ,
7994 WINED3DRS_BLENDOP ,
7995 WINED3DRS_COLORWRITEENABLE ,
7996 WINED3DRS_DESTBLEND ,
7997 WINED3DRS_DITHERENABLE ,
7998 WINED3DRS_FILLMODE ,
7999 WINED3DRS_FOGDENSITY ,
8000 WINED3DRS_FOGEND ,
8001 WINED3DRS_FOGSTART ,
8002 WINED3DRS_LASTPIXEL ,
8003 WINED3DRS_SHADEMODE ,
8004 WINED3DRS_SRCBLEND ,
8005 WINED3DRS_STENCILENABLE ,
8006 WINED3DRS_STENCILFAIL ,
8007 WINED3DRS_STENCILFUNC ,
8008 WINED3DRS_STENCILMASK ,
8009 WINED3DRS_STENCILPASS ,
8010 WINED3DRS_STENCILREF ,
8011 WINED3DRS_STENCILWRITEMASK ,
8012 WINED3DRS_STENCILZFAIL ,
8013 WINED3DRS_TEXTUREFACTOR ,
8014 WINED3DRS_WRAP0 ,
8015 WINED3DRS_WRAP1 ,
8016 WINED3DRS_WRAP2 ,
8017 WINED3DRS_WRAP3 ,
8018 WINED3DRS_WRAP4 ,
8019 WINED3DRS_WRAP5 ,
8020 WINED3DRS_WRAP6 ,
8021 WINED3DRS_WRAP7 ,
8022 WINED3DRS_ZENABLE ,
8023 WINED3DRS_ZFUNC ,
8024 WINED3DRS_ZWRITEENABLE
8027 const DWORD SavedPixelStates_T[NUM_SAVEDPIXELSTATES_T] = {
8028 WINED3DTSS_ADDRESSW ,
8029 WINED3DTSS_ALPHAARG0 ,
8030 WINED3DTSS_ALPHAARG1 ,
8031 WINED3DTSS_ALPHAARG2 ,
8032 WINED3DTSS_ALPHAOP ,
8033 WINED3DTSS_BUMPENVLOFFSET ,
8034 WINED3DTSS_BUMPENVLSCALE ,
8035 WINED3DTSS_BUMPENVMAT00 ,
8036 WINED3DTSS_BUMPENVMAT01 ,
8037 WINED3DTSS_BUMPENVMAT10 ,
8038 WINED3DTSS_BUMPENVMAT11 ,
8039 WINED3DTSS_COLORARG0 ,
8040 WINED3DTSS_COLORARG1 ,
8041 WINED3DTSS_COLORARG2 ,
8042 WINED3DTSS_COLOROP ,
8043 WINED3DTSS_RESULTARG ,
8044 WINED3DTSS_TEXCOORDINDEX ,
8045 WINED3DTSS_TEXTURETRANSFORMFLAGS
8048 const DWORD SavedPixelStates_S[NUM_SAVEDPIXELSTATES_S] = {
8049 WINED3DSAMP_ADDRESSU ,
8050 WINED3DSAMP_ADDRESSV ,
8051 WINED3DSAMP_ADDRESSW ,
8052 WINED3DSAMP_BORDERCOLOR ,
8053 WINED3DSAMP_MAGFILTER ,
8054 WINED3DSAMP_MINFILTER ,
8055 WINED3DSAMP_MIPFILTER ,
8056 WINED3DSAMP_MIPMAPLODBIAS ,
8057 WINED3DSAMP_MAXMIPLEVEL ,
8058 WINED3DSAMP_MAXANISOTROPY ,
8059 WINED3DSAMP_SRGBTEXTURE ,
8060 WINED3DSAMP_ELEMENTINDEX
8063 const DWORD SavedVertexStates_R[NUM_SAVEDVERTEXSTATES_R] = {
8064 WINED3DRS_AMBIENT ,
8065 WINED3DRS_AMBIENTMATERIALSOURCE ,
8066 WINED3DRS_CLIPPING ,
8067 WINED3DRS_CLIPPLANEENABLE ,
8068 WINED3DRS_COLORVERTEX ,
8069 WINED3DRS_DIFFUSEMATERIALSOURCE ,
8070 WINED3DRS_EMISSIVEMATERIALSOURCE ,
8071 WINED3DRS_FOGDENSITY ,
8072 WINED3DRS_FOGEND ,
8073 WINED3DRS_FOGSTART ,
8074 WINED3DRS_FOGTABLEMODE ,
8075 WINED3DRS_FOGVERTEXMODE ,
8076 WINED3DRS_INDEXEDVERTEXBLENDENABLE ,
8077 WINED3DRS_LIGHTING ,
8078 WINED3DRS_LOCALVIEWER ,
8079 WINED3DRS_MULTISAMPLEANTIALIAS ,
8080 WINED3DRS_MULTISAMPLEMASK ,
8081 WINED3DRS_NORMALIZENORMALS ,
8082 WINED3DRS_PATCHEDGESTYLE ,
8083 WINED3DRS_POINTSCALE_A ,
8084 WINED3DRS_POINTSCALE_B ,
8085 WINED3DRS_POINTSCALE_C ,
8086 WINED3DRS_POINTSCALEENABLE ,
8087 WINED3DRS_POINTSIZE ,
8088 WINED3DRS_POINTSIZE_MAX ,
8089 WINED3DRS_POINTSIZE_MIN ,
8090 WINED3DRS_POINTSPRITEENABLE ,
8091 WINED3DRS_RANGEFOGENABLE ,
8092 WINED3DRS_SPECULARMATERIALSOURCE ,
8093 WINED3DRS_TWEENFACTOR ,
8094 WINED3DRS_VERTEXBLEND ,
8095 WINED3DRS_CULLMODE ,
8096 WINED3DRS_FOGCOLOR
8099 const DWORD SavedVertexStates_T[NUM_SAVEDVERTEXSTATES_T] = {
8100 WINED3DTSS_TEXCOORDINDEX ,
8101 WINED3DTSS_TEXTURETRANSFORMFLAGS
8104 const DWORD SavedVertexStates_S[NUM_SAVEDVERTEXSTATES_S] = {
8105 WINED3DSAMP_DMAPOFFSET
8108 void IWineD3DDeviceImpl_MarkStateDirty(IWineD3DDeviceImpl *This, DWORD state) {
8109 DWORD rep = This->StateTable[state].representative;
8110 DWORD idx;
8111 BYTE shift;
8112 UINT i;
8113 WineD3DContext *context;
8115 if(!rep) return;
8116 for(i = 0; i < This->numContexts; i++) {
8117 context = This->contexts[i];
8118 if(isStateDirty(context, rep)) continue;
8120 context->dirtyArray[context->numDirtyEntries++] = rep;
8121 idx = rep >> 5;
8122 shift = rep & 0x1f;
8123 context->isStateDirty[idx] |= (1 << shift);
8127 void get_drawable_size_pbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8128 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8129 /* The drawable size of a pbuffer render target is the current pbuffer size
8131 *width = dev->pbufferWidth;
8132 *height = dev->pbufferHeight;
8135 void get_drawable_size_fbo(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8136 /* The drawable size of a fbo target is the opengl texture size, which is the power of two size
8138 *width = This->pow2Width;
8139 *height = This->pow2Height;
8142 void get_drawable_size_backbuffer(IWineD3DSurfaceImpl *This, UINT *width, UINT *height) {
8143 IWineD3DDeviceImpl *dev = This->resource.wineD3DDevice;
8144 /* The drawable size of a backbuffer / aux buffer offscreen target is the size of the
8145 * current context's drawable, which is the size of the back buffer of the swapchain
8146 * the active context belongs to. The back buffer of the swapchain is stored as the
8147 * surface the context belongs to.
8149 *width = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Width;
8150 *height = ((IWineD3DSurfaceImpl *) dev->activeContext->surface)->currentDesc.Height;